LCOV - code coverage report
Current view: top level - netwerk/protocol/http - nsHttpConnectionMgr.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 37 2472 1.5 %
Date: 2018-08-07 16:42:27 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* vim:set ts=4 sw=4 sts=4 et cin: */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : // HttpLog.h should generally be included first
       7             : #include "HttpLog.h"
       8             : 
       9             : // Log on level :5, instead of default :4.
      10             : #undef LOG
      11             : #define LOG(args) LOG5(args)
      12             : #undef LOG_ENABLED
      13             : #define LOG_ENABLED() LOG5_ENABLED()
      14             : 
      15             : #include "nsHttpConnectionMgr.h"
      16             : #include "nsHttpConnection.h"
      17             : #include "nsHttpHandler.h"
      18             : #include "nsIHttpChannelInternal.h"
      19             : #include "nsNetCID.h"
      20             : #include "nsCOMPtr.h"
      21             : #include "nsNetUtil.h"
      22             : #include "mozilla/net/DNS.h"
      23             : #include "nsISocketTransport.h"
      24             : #include "nsISSLSocketControl.h"
      25             : #include "mozilla/Services.h"
      26             : #include "mozilla/Telemetry.h"
      27             : #include "mozilla/net/DashboardTypes.h"
      28             : #include "NullHttpTransaction.h"
      29             : #include "nsIDNSRecord.h"
      30             : #include "nsITransport.h"
      31             : #include "nsInterfaceRequestorAgg.h"
      32             : #include "nsIRequestContext.h"
      33             : #include "nsISocketTransportService.h"
      34             : #include <algorithm>
      35             : #include "mozilla/ChaosMode.h"
      36             : #include "mozilla/Unused.h"
      37             : #include "nsIURI.h"
      38             : 
      39             : #include "mozilla/Move.h"
      40             : #include "mozilla/Telemetry.h"
      41             : 
      42             : namespace mozilla {
      43             : namespace net {
      44             : 
      45             : //-----------------------------------------------------------------------------
      46             : 
      47           0 : NS_IMPL_ISUPPORTS(nsHttpConnectionMgr, nsIObserver)
      48             : 
      49             : // This function decides the transaction's order in the pending queue.
      50             : // Given two transactions t1 and t2, returning true means that t2 is
      51             : // more important than t1 and thus should be dispatched first.
      52             : static bool
      53           0 : TransactionComparator(nsHttpTransaction *t1, nsHttpTransaction *t2)
      54             : {
      55             :     bool t1Blocking =
      56           0 :         t1->Caps() & (NS_HTTP_LOAD_AS_BLOCKING | NS_HTTP_LOAD_UNBLOCKED);
      57             :     bool t2Blocking =
      58           0 :         t2->Caps() & (NS_HTTP_LOAD_AS_BLOCKING | NS_HTTP_LOAD_UNBLOCKED);
      59             : 
      60           0 :     if (t1Blocking > t2Blocking) {
      61             :         return false;
      62             :     }
      63             : 
      64           0 :     if (t2Blocking > t1Blocking) {
      65             :         return true;
      66             :     }
      67             : 
      68           0 :     return t1->Priority() >= t2->Priority();
      69             : }
      70             : 
      71             : void
      72           0 : nsHttpConnectionMgr::InsertTransactionSorted(nsTArray<RefPtr<nsHttpConnectionMgr::PendingTransactionInfo> > &pendingQ,
      73             :                                              nsHttpConnectionMgr::PendingTransactionInfo *pendingTransInfo,
      74             :                                              bool aInsertAsFirstForTheSamePriority /*= false*/)
      75             : {
      76             :     // insert the transaction into the front of the queue based on following rules:
      77             :     // 1. The transaction has NS_HTTP_LOAD_AS_BLOCKING or NS_HTTP_LOAD_UNBLOCKED.
      78             :     // 2. The transaction's priority is higher.
      79             :     //
      80             :     // search in reverse order under the assumption that many of the
      81             :     // existing transactions will have the same priority (usually 0).
      82             : 
      83           0 :     nsHttpTransaction *trans = pendingTransInfo->mTransaction;
      84             : 
      85           0 :     for (int32_t i = pendingQ.Length() - 1; i >= 0; --i) {
      86           0 :         nsHttpTransaction *t = pendingQ[i]->mTransaction;
      87           0 :         if (TransactionComparator(trans, t)) {
      88           0 :             if (ChaosMode::isActive(ChaosFeature::NetworkScheduling) || aInsertAsFirstForTheSamePriority) {
      89             :                 int32_t samePriorityCount;
      90           0 :                 for (samePriorityCount = 0; i - samePriorityCount >= 0; ++samePriorityCount) {
      91           0 :                     if (pendingQ[i - samePriorityCount]->mTransaction->Priority() != trans->Priority()) {
      92             :                         break;
      93             :                     }
      94             :                 }
      95           0 :                 if (aInsertAsFirstForTheSamePriority) {
      96             :                     i -= samePriorityCount;
      97             :                 } else {
      98             :                     // skip over 0...all of the elements with the same priority.
      99           0 :                     i -= ChaosMode::randomUint32LessThan(samePriorityCount + 1);
     100             :                 }
     101             :             }
     102           0 :             pendingQ.InsertElementAt(i+1, pendingTransInfo);
     103           0 :             return;
     104             :         }
     105             :     }
     106           0 :     pendingQ.InsertElementAt(0, pendingTransInfo);
     107             : }
     108             : 
     109             : //-----------------------------------------------------------------------------
     110             : 
     111           0 : nsHttpConnectionMgr::nsHttpConnectionMgr()
     112             :     : mReentrantMonitor("nsHttpConnectionMgr.mReentrantMonitor")
     113             :     , mMaxUrgentExcessiveConns(0)
     114             :     , mMaxConns(0)
     115             :     , mMaxPersistConnsPerHost(0)
     116             :     , mMaxPersistConnsPerProxy(0)
     117             :     , mMaxRequestDelay(0)
     118             :     , mThrottleEnabled(false)
     119             :     , mThrottleVersion(2)
     120             :     , mThrottleSuspendFor(0)
     121             :     , mThrottleResumeFor(0)
     122             :     , mThrottleReadLimit(0)
     123             :     , mThrottleReadInterval(0)
     124             :     , mThrottleHoldTime(0)
     125             :     , mThrottleMaxTime(0)
     126             :     , mIsShuttingDown(false)
     127             :     , mNumActiveConns(0)
     128             :     , mNumIdleConns(0)
     129             :     , mNumSpdyActiveConns(0)
     130             :     , mNumHalfOpenConns(0)
     131             :     , mTimeOfNextWakeUp(UINT64_MAX)
     132             :     , mPruningNoTraffic(false)
     133             :     , mTimeoutTickArmed(false)
     134             :     , mTimeoutTickNext(1)
     135             :     , mCurrentTopLevelOuterContentWindowId(0)
     136             :     , mThrottlingInhibitsReading(false)
     137             :     , mActiveTabTransactionsExist(false)
     138           0 :     , mActiveTabUnthrottledTransactionsExist(false)
     139             : {
     140           0 :     LOG(("Creating nsHttpConnectionMgr @%p\n", this));
     141           0 : }
     142             : 
     143           0 : nsHttpConnectionMgr::~nsHttpConnectionMgr()
     144             : {
     145           0 :     LOG(("Destroying nsHttpConnectionMgr @%p\n", this));
     146           0 :     MOZ_ASSERT(mCoalescingHash.Count() == 0);
     147           0 :     if (mTimeoutTick)
     148           0 :         mTimeoutTick->Cancel();
     149           0 : }
     150             : 
     151             : nsresult
     152           0 : nsHttpConnectionMgr::EnsureSocketThreadTarget()
     153             : {
     154           0 :     nsCOMPtr<nsIEventTarget> sts;
     155           0 :     nsCOMPtr<nsIIOService> ioService = services::GetIOService();
     156           0 :     if (ioService) {
     157             :         nsCOMPtr<nsISocketTransportService> realSTS =
     158           0 :             services::GetSocketTransportService();
     159           0 :         sts = do_QueryInterface(realSTS);
     160             :     }
     161             : 
     162           0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     163             : 
     164             :     // do nothing if already initialized or if we've shut down
     165           0 :     if (mSocketThreadTarget || mIsShuttingDown)
     166             :         return NS_OK;
     167             : 
     168           0 :     mSocketThreadTarget = sts;
     169             : 
     170           0 :     return sts ? NS_OK : NS_ERROR_NOT_AVAILABLE;
     171             : }
     172             : 
     173             : nsresult
     174           0 : nsHttpConnectionMgr::Init(uint16_t maxUrgentExcessiveConns,
     175             :                           uint16_t maxConns,
     176             :                           uint16_t maxPersistConnsPerHost,
     177             :                           uint16_t maxPersistConnsPerProxy,
     178             :                           uint16_t maxRequestDelay,
     179             :                           bool throttleEnabled,
     180             :                           uint32_t throttleVersion,
     181             :                           uint32_t throttleSuspendFor,
     182             :                           uint32_t throttleResumeFor,
     183             :                           uint32_t throttleReadLimit,
     184             :                           uint32_t throttleReadInterval,
     185             :                           uint32_t throttleHoldTime,
     186             :                           uint32_t throttleMaxTime)
     187             : {
     188           0 :     LOG(("nsHttpConnectionMgr::Init\n"));
     189             : 
     190             :     {
     191           0 :         ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     192             : 
     193           0 :         mMaxUrgentExcessiveConns = maxUrgentExcessiveConns;
     194           0 :         mMaxConns = maxConns;
     195           0 :         mMaxPersistConnsPerHost = maxPersistConnsPerHost;
     196           0 :         mMaxPersistConnsPerProxy = maxPersistConnsPerProxy;
     197           0 :         mMaxRequestDelay = maxRequestDelay;
     198             : 
     199           0 :         mThrottleEnabled = throttleEnabled;
     200           0 :         mThrottleVersion = throttleVersion;
     201           0 :         mThrottleSuspendFor = throttleSuspendFor;
     202           0 :         mThrottleResumeFor = throttleResumeFor;
     203           0 :         mThrottleReadLimit = throttleReadLimit;
     204           0 :         mThrottleReadInterval = throttleReadInterval;
     205           0 :         mThrottleHoldTime = throttleHoldTime;
     206           0 :         mThrottleMaxTime = TimeDuration::FromMilliseconds(throttleMaxTime);
     207             : 
     208           0 :         mIsShuttingDown = false;
     209             :     }
     210             : 
     211           0 :     return EnsureSocketThreadTarget();
     212             : }
     213             : 
     214             : class BoolWrapper : public ARefBase
     215             : {
     216             : public:
     217           0 :     BoolWrapper() : mBool(false) {}
     218           0 :     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BoolWrapper, override)
     219             : 
     220             : public: // intentional!
     221             :     bool mBool;
     222             : 
     223             : private:
     224           0 :     virtual ~BoolWrapper() = default;
     225             : };
     226             : 
     227             : nsresult
     228           0 : nsHttpConnectionMgr::Shutdown()
     229             : {
     230           0 :     LOG(("nsHttpConnectionMgr::Shutdown\n"));
     231             : 
     232           0 :     RefPtr<BoolWrapper> shutdownWrapper = new BoolWrapper();
     233             :     {
     234           0 :         ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     235             : 
     236             :         // do nothing if already shutdown
     237           0 :         if (!mSocketThreadTarget)
     238           0 :             return NS_OK;
     239             : 
     240           0 :         nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgShutdown,
     241           0 :                                 0, shutdownWrapper);
     242             : 
     243             :         // release our reference to the STS to prevent further events
     244             :         // from being posted.  this is how we indicate that we are
     245             :         // shutting down.
     246           0 :         mIsShuttingDown = true;
     247           0 :         mSocketThreadTarget = nullptr;
     248             : 
     249           0 :         if (NS_FAILED(rv)) {
     250           0 :             NS_WARNING("unable to post SHUTDOWN message");
     251           0 :             return rv;
     252             :         }
     253             :     }
     254             : 
     255             :     // wait for shutdown event to complete
     256           0 :     SpinEventLoopUntil([&, shutdownWrapper]() { return shutdownWrapper->mBool; });
     257             : 
     258           0 :     return NS_OK;
     259             : }
     260             : 
     261             : class ConnEvent : public Runnable
     262             : {
     263             : public:
     264           0 :   ConnEvent(nsHttpConnectionMgr* mgr,
     265             :             nsConnEventHandler handler,
     266             :             int32_t iparam,
     267             :             ARefBase* vparam)
     268           0 :     : Runnable("net::ConnEvent")
     269             :     , mMgr(mgr)
     270             :     , mHandler(handler)
     271             :     , mIParam(iparam)
     272           0 :     , mVParam(vparam)
     273             :   {
     274           0 :   }
     275             : 
     276           0 :   NS_IMETHOD Run() override
     277             :   {
     278           0 :     (mMgr->*mHandler)(mIParam, mVParam);
     279           0 :     return NS_OK;
     280             :     }
     281             : 
     282             : private:
     283           0 :     virtual ~ConnEvent() = default;
     284             : 
     285             :     RefPtr<nsHttpConnectionMgr>  mMgr;
     286             :     nsConnEventHandler           mHandler;
     287             :     int32_t                      mIParam;
     288             :     RefPtr<ARefBase>             mVParam;
     289             : };
     290             : 
     291             : nsresult
     292           0 : nsHttpConnectionMgr::PostEvent(nsConnEventHandler handler,
     293             :                                int32_t iparam, ARefBase *vparam)
     294             : {
     295           0 :     Unused << EnsureSocketThreadTarget();
     296             : 
     297           0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     298             : 
     299             :     nsresult rv;
     300           0 :     if (!mSocketThreadTarget) {
     301           0 :         NS_WARNING("cannot post event if not initialized");
     302           0 :         rv = NS_ERROR_NOT_INITIALIZED;
     303             :     }
     304             :     else {
     305           0 :         nsCOMPtr<nsIRunnable> event = new ConnEvent(this, handler, iparam, vparam);
     306           0 :         rv = mSocketThreadTarget->Dispatch(event, NS_DISPATCH_NORMAL);
     307             :     }
     308           0 :     return rv;
     309             : }
     310             : 
     311             : void
     312           0 : nsHttpConnectionMgr::PruneDeadConnectionsAfter(uint32_t timeInSeconds)
     313             : {
     314           0 :     LOG(("nsHttpConnectionMgr::PruneDeadConnectionsAfter\n"));
     315             : 
     316           0 :     if(!mTimer)
     317           0 :         mTimer = NS_NewTimer();
     318             : 
     319             :     // failure to create a timer is not a fatal error, but idle connections
     320             :     // will not be cleaned up until we try to use them.
     321           0 :     if (mTimer) {
     322           0 :         mTimeOfNextWakeUp = timeInSeconds + NowInSeconds();
     323           0 :         mTimer->Init(this, timeInSeconds*1000, nsITimer::TYPE_ONE_SHOT);
     324             :     } else {
     325           0 :         NS_WARNING("failed to create: timer for pruning the dead connections!");
     326             :     }
     327           0 : }
     328             : 
     329             : void
     330           0 : nsHttpConnectionMgr::ConditionallyStopPruneDeadConnectionsTimer()
     331             : {
     332             :     // Leave the timer in place if there are connections that potentially
     333             :     // need management
     334           0 :     if (mNumIdleConns || (mNumActiveConns && gHttpHandler->IsSpdyEnabled()))
     335             :         return;
     336             : 
     337           0 :     LOG(("nsHttpConnectionMgr::StopPruneDeadConnectionsTimer\n"));
     338             : 
     339             :     // Reset mTimeOfNextWakeUp so that we can find a new shortest value.
     340           0 :     mTimeOfNextWakeUp = UINT64_MAX;
     341           0 :     if (mTimer) {
     342           0 :         mTimer->Cancel();
     343           0 :         mTimer = nullptr;
     344             :     }
     345             : }
     346             : 
     347             : void
     348           0 : nsHttpConnectionMgr::ConditionallyStopTimeoutTick()
     349             : {
     350           0 :     LOG(("nsHttpConnectionMgr::ConditionallyStopTimeoutTick "
     351             :          "armed=%d active=%d\n", mTimeoutTickArmed, mNumActiveConns));
     352             : 
     353           0 :     if (!mTimeoutTickArmed)
     354             :         return;
     355             : 
     356           0 :     if (mNumActiveConns)
     357             :         return;
     358             : 
     359           0 :     LOG(("nsHttpConnectionMgr::ConditionallyStopTimeoutTick stop==true\n"));
     360             : 
     361           0 :     mTimeoutTick->Cancel();
     362           0 :     mTimeoutTickArmed = false;
     363             : }
     364             : 
     365             : //-----------------------------------------------------------------------------
     366             : // nsHttpConnectionMgr::nsIObserver
     367             : //-----------------------------------------------------------------------------
     368             : 
     369             : NS_IMETHODIMP
     370           0 : nsHttpConnectionMgr::Observe(nsISupports *subject,
     371             :                              const char *topic,
     372             :                              const char16_t *data)
     373             : {
     374           0 :     LOG(("nsHttpConnectionMgr::Observe [topic=\"%s\"]\n", topic));
     375             : 
     376           0 :     if (0 == strcmp(topic, NS_TIMER_CALLBACK_TOPIC)) {
     377           0 :         nsCOMPtr<nsITimer> timer = do_QueryInterface(subject);
     378           0 :         if (timer == mTimer) {
     379           0 :             Unused << PruneDeadConnections();
     380           0 :         } else if (timer == mTimeoutTick) {
     381           0 :             TimeoutTick();
     382           0 :         } else if (timer == mTrafficTimer) {
     383           0 :             Unused << PruneNoTraffic();
     384           0 :         } else if (timer == mThrottleTicker) {
     385           0 :             ThrottlerTick();
     386           0 :         } else if (timer == mDelayedResumeReadTimer) {
     387           0 :             ResumeBackgroundThrottledTransactions();
     388             :         } else {
     389           0 :             MOZ_ASSERT(false, "unexpected timer-callback");
     390             :             LOG(("Unexpected timer object\n"));
     391             :             return NS_ERROR_UNEXPECTED;
     392             :         }
     393             :     }
     394             : 
     395             :     return NS_OK;
     396             : }
     397             : 
     398             : 
     399             : //-----------------------------------------------------------------------------
     400             : 
     401             : nsresult
     402           0 : nsHttpConnectionMgr::AddTransaction(nsHttpTransaction *trans, int32_t priority)
     403             : {
     404           0 :     LOG(("nsHttpConnectionMgr::AddTransaction [trans=%p %d]\n", trans, priority));
     405           0 :     return PostEvent(&nsHttpConnectionMgr::OnMsgNewTransaction, priority, trans);
     406             : }
     407             : 
     408             : nsresult
     409           0 : nsHttpConnectionMgr::RescheduleTransaction(nsHttpTransaction *trans, int32_t priority)
     410             : {
     411           0 :     LOG(("nsHttpConnectionMgr::RescheduleTransaction [trans=%p %d]\n", trans, priority));
     412           0 :     return PostEvent(&nsHttpConnectionMgr::OnMsgReschedTransaction, priority, trans);
     413             : }
     414             : 
     415             : void
     416           0 : nsHttpConnectionMgr::UpdateClassOfServiceOnTransaction(nsHttpTransaction *trans, uint32_t classOfService)
     417             : {
     418           0 :     LOG(("nsHttpConnectionMgr::UpdateClassOfServiceOnTransaction [trans=%p classOfService=%" PRIu32 "]\n",
     419             :          trans, static_cast<uint32_t>(classOfService)));
     420           0 :     Unused << PostEvent(&nsHttpConnectionMgr::OnMsgUpdateClassOfServiceOnTransaction,
     421             :                         static_cast<int32_t>(classOfService), trans);
     422           0 : }
     423             : 
     424             : nsresult
     425           0 : nsHttpConnectionMgr::CancelTransaction(nsHttpTransaction *trans, nsresult reason)
     426             : {
     427           0 :     LOG(("nsHttpConnectionMgr::CancelTransaction [trans=%p reason=%" PRIx32 "]\n",
     428             :          trans, static_cast<uint32_t>(reason)));
     429           0 :     return PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransaction,
     430           0 :                      static_cast<int32_t>(reason), trans);
     431             : }
     432             : 
     433             : nsresult
     434           0 : nsHttpConnectionMgr::PruneDeadConnections()
     435             : {
     436           0 :     return PostEvent(&nsHttpConnectionMgr::OnMsgPruneDeadConnections);
     437             : }
     438             : 
     439             : //
     440             : // Called after a timeout. Check for active connections that have had no
     441             : // traffic since they were "marked" and nuke them.
     442             : nsresult
     443           0 : nsHttpConnectionMgr::PruneNoTraffic()
     444             : {
     445           0 :     LOG(("nsHttpConnectionMgr::PruneNoTraffic\n"));
     446           0 :     mPruningNoTraffic = true;
     447           0 :     return PostEvent(&nsHttpConnectionMgr::OnMsgPruneNoTraffic);
     448             : }
     449             : 
     450             : nsresult
     451           0 : nsHttpConnectionMgr::VerifyTraffic()
     452             : {
     453           0 :     LOG(("nsHttpConnectionMgr::VerifyTraffic\n"));
     454           0 :     return PostEvent(&nsHttpConnectionMgr::OnMsgVerifyTraffic);
     455             : }
     456             : 
     457             : nsresult
     458           0 : nsHttpConnectionMgr::DoShiftReloadConnectionCleanup(nsHttpConnectionInfo *aCI)
     459             : {
     460           0 :     return PostEvent(&nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup,
     461           0 :                      0, aCI);
     462             : }
     463             : 
     464             : class SpeculativeConnectArgs : public ARefBase
     465             : {
     466             : public:
     467           0 :     SpeculativeConnectArgs()
     468           0 :         : mParallelSpeculativeConnectLimit(0)
     469             :         , mIgnoreIdle(false)
     470             :         , mIsFromPredictor(false)
     471             :         , mAllow1918(false)
     472             :     {
     473             :         mOverridesOK = false;
     474             :     }
     475             :     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SpeculativeConnectArgs, override)
     476             : 
     477             : public: // intentional!
     478             :     RefPtr<NullHttpTransaction> mTrans;
     479             : 
     480           0 :     bool mOverridesOK;
     481             :     uint32_t mParallelSpeculativeConnectLimit;
     482             :     bool mIgnoreIdle;
     483             :     bool mIsFromPredictor;
     484             :     bool mAllow1918;
     485           0 : 
     486             : private:
     487             :     virtual ~SpeculativeConnectArgs() = default;
     488             :     NS_DECL_OWNINGTHREAD
     489             : };
     490           0 : 
     491             : nsresult
     492           0 : nsHttpConnectionMgr::SpeculativeConnect(nsHttpConnectionInfo *ci,
     493             :                                         nsIInterfaceRequestor *callbacks,
     494           0 :                                         uint32_t caps,
     495             :                                         NullHttpTransaction *nullTransaction)
     496             : {
     497           0 :     MOZ_ASSERT(NS_IsMainThread(), "nsHttpConnectionMgr::SpeculativeConnect called off main thread!");
     498             : 
     499             :     if (!IsNeckoChild()) {
     500             :         // HACK: make sure PSM gets initialized on the main thread.
     501           0 :         net_EnsurePSMInit();
     502             :     }
     503           0 : 
     504             :     LOG(("nsHttpConnectionMgr::SpeculativeConnect [ci=%s]\n",
     505             :          ci->HashKey().get()));
     506             : 
     507           0 :     nsCOMPtr<nsISpeculativeConnectionOverrider> overrider =
     508           0 :         do_GetInterface(callbacks);
     509             : 
     510             :     bool allow1918 = overrider ? overrider->GetAllow1918() : false;
     511             : 
     512             :     // Hosts that are Local IP Literals should not be speculatively
     513           0 :     // connected - Bug 853423.
     514             :     if ((!allow1918) && ci && ci->HostIsLocalIPLiteral()) {
     515             :         LOG(("nsHttpConnectionMgr::SpeculativeConnect skipping RFC1918 "
     516             :              "address [%s]", ci->Origin()));
     517           0 :         return NS_OK;
     518           0 :     }
     519             : 
     520           0 :     RefPtr<SpeculativeConnectArgs> args = new SpeculativeConnectArgs();
     521           0 : 
     522           0 :     // Wrap up the callbacks and the target to ensure they're released on the target
     523           0 :     // thread properly.
     524             :     nsCOMPtr<nsIInterfaceRequestor> wrappedCallbacks;
     525           0 :     NS_NewInterfaceRequestorAggregation(callbacks, nullptr, getter_AddRefs(wrappedCallbacks));
     526           0 : 
     527           0 :     caps |= ci->GetAnonymous() ? NS_HTTP_LOAD_ANONYMOUS : 0;
     528           0 :     caps |= NS_HTTP_ERROR_SOFTLY;
     529           0 :     args->mTrans =
     530           0 :         nullTransaction ? nullTransaction : new NullHttpTransaction(ci, wrappedCallbacks, caps);
     531           0 : 
     532             :     if (overrider) {
     533             :         args->mOverridesOK = true;
     534           0 :         args->mParallelSpeculativeConnectLimit =
     535             :             overrider->GetParallelSpeculativeConnectLimit();
     536             :         args->mIgnoreIdle = overrider->GetIgnoreIdle();
     537             :         args->mIsFromPredictor = overrider->GetIsFromPredictor();
     538           0 :         args->mAllow1918 = overrider->GetAllow1918();
     539             :     }
     540           0 : 
     541             :     return PostEvent(&nsHttpConnectionMgr::OnMsgSpeculativeConnect, 0, args);
     542           0 : }
     543           0 : 
     544           0 : nsresult
     545           0 : nsHttpConnectionMgr::GetSocketThreadTarget(nsIEventTarget **target)
     546             : {
     547             :     Unused << EnsureSocketThreadTarget();
     548             : 
     549           0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     550             :     nsCOMPtr<nsIEventTarget> temp(mSocketThreadTarget);
     551           0 :     temp.forget(target);
     552           0 :     return NS_OK;
     553             : }
     554             : 
     555             : nsresult
     556             : nsHttpConnectionMgr::ReclaimConnection(nsHttpConnection *conn)
     557             : {
     558             :     LOG(("nsHttpConnectionMgr::ReclaimConnection [conn=%p]\n", conn));
     559             :     return PostEvent(&nsHttpConnectionMgr::OnMsgReclaimConnection, 0, conn);
     560           0 : }
     561             : 
     562           0 : // A structure used to marshall 2 pointers across the various necessary
     563           0 : // threads to complete an HTTP upgrade.
     564             : class nsCompleteUpgradeData : public ARefBase
     565           0 : {
     566             : public:
     567             :     nsCompleteUpgradeData(nsAHttpConnection *aConn,
     568             :                           nsIHttpUpgradeListener *aListener)
     569             :         : mConn(aConn)
     570           0 :         , mUpgradeListener(aListener) { }
     571             : 
     572             :     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsCompleteUpgradeData, override)
     573             : 
     574           0 :     RefPtr<nsAHttpConnection> mConn;
     575             :     nsCOMPtr<nsIHttpUpgradeListener> mUpgradeListener;
     576             : private:
     577             :     virtual ~nsCompleteUpgradeData() = default;
     578           0 : };
     579           0 : 
     580             : nsresult
     581             : nsHttpConnectionMgr::CompleteUpgrade(nsAHttpConnection *aConn,
     582             :                                      nsIHttpUpgradeListener *aUpgradeListener)
     583           0 : {
     584             :     RefPtr<nsCompleteUpgradeData> data =
     585           0 :         new nsCompleteUpgradeData(aConn, aUpgradeListener);
     586           0 :     return PostEvent(&nsHttpConnectionMgr::OnMsgCompleteUpgrade, 0, data);
     587           0 : }
     588             : 
     589             : nsresult
     590             : nsHttpConnectionMgr::UpdateParam(nsParamName name, uint16_t value)
     591           0 : {
     592             :     uint32_t param = (uint32_t(name) << 16) | uint32_t(value);
     593           0 :     return PostEvent(&nsHttpConnectionMgr::OnMsgUpdateParam,
     594           0 :                      static_cast<int32_t>(param), nullptr);
     595             : }
     596             : 
     597             : nsresult
     598           0 : nsHttpConnectionMgr::ProcessPendingQ(nsHttpConnectionInfo *ci)
     599             : {
     600           0 :     LOG(("nsHttpConnectionMgr::ProcessPendingQ [ci=%s]\n", ci->HashKey().get()));
     601           0 :     return PostEvent(&nsHttpConnectionMgr::OnMsgProcessPendingQ, 0, ci);
     602             : }
     603             : 
     604             : nsresult
     605           0 : nsHttpConnectionMgr::ProcessPendingQ()
     606             : {
     607           0 :     LOG(("nsHttpConnectionMgr::ProcessPendingQ [All CI]\n"));
     608           0 :     return PostEvent(&nsHttpConnectionMgr::OnMsgProcessPendingQ, 0, nullptr);
     609           0 : }
     610             : 
     611             : void
     612           0 : nsHttpConnectionMgr::OnMsgUpdateRequestTokenBucket(int32_t, ARefBase *param)
     613             : {
     614             :     EventTokenBucket *tokenBucket = static_cast<EventTokenBucket *>(param);
     615             :     gHttpHandler->SetRequestTokenBucket(tokenBucket);
     616           0 : }
     617           0 : 
     618             : nsresult
     619             : nsHttpConnectionMgr::UpdateRequestTokenBucket(EventTokenBucket *aBucket)
     620             : {
     621           0 :     // Call From main thread when a new EventTokenBucket has been made in order
     622             :     // to post the new value to the socket thread.
     623           0 :     return PostEvent(&nsHttpConnectionMgr::OnMsgUpdateRequestTokenBucket,
     624             :                      0, aBucket);
     625           0 : }
     626           0 : 
     627           0 : nsresult
     628           0 : nsHttpConnectionMgr::ClearConnectionHistory()
     629           0 : {
     630           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
     631           0 : 
     632           0 :     for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
     633           0 :         RefPtr<nsConnectionEntry> ent = iter.Data();
     634           0 :         if (ent->mIdleConns.Length()    == 0 &&
     635             :             ent->mActiveConns.Length()  == 0 &&
     636             :             ent->mHalfOpens.Length()    == 0 &&
     637             :             ent->mUrgentStartQ.Length() == 0 &&
     638           0 :             ent->PendingQLength()       == 0 &&
     639             :             ent->mHalfOpenFastOpenBackups.Length() == 0 &&
     640             :             !ent->mDoNotDestroy) {
     641             :             iter.Remove();
     642           0 :         }
     643             :     }
     644           0 : 
     645           0 :     return NS_OK;
     646             : }
     647             : 
     648           0 : nsresult
     649             : nsHttpConnectionMgr::CloseIdleConnection(nsHttpConnection *conn)
     650             : {
     651             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
     652           0 :     LOG(("nsHttpConnectionMgr::CloseIdleConnection %p conn=%p",
     653             :          this, conn));
     654           0 : 
     655           0 :     if (!conn->ConnectionInfo()) {
     656             :         return NS_ERROR_UNEXPECTED;
     657             :     }
     658           0 : 
     659           0 :     nsConnectionEntry *ent = mCT.GetWeak(conn->ConnectionInfo()->HashKey());
     660           0 : 
     661           0 :     RefPtr<nsHttpConnection> deleteProtector(conn);
     662             :     if (!ent || !ent->mIdleConns.RemoveElement(conn))
     663             :         return NS_ERROR_UNEXPECTED;
     664             : 
     665           0 :     conn->Close(NS_ERROR_ABORT);
     666             :     mNumIdleConns--;
     667           0 :     ConditionallyStopPruneDeadConnectionsTimer();
     668             :     return NS_OK;
     669           0 : }
     670             : 
     671             : nsresult
     672           0 : nsHttpConnectionMgr::RemoveIdleConnection(nsHttpConnection *conn)
     673             : {
     674             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
     675             : 
     676           0 :     LOG(("nsHttpConnectionMgr::RemoveIdleConnection %p conn=%p",
     677             :          this, conn));
     678           0 : 
     679             :     if (!conn->ConnectionInfo()) {
     680             :         return NS_ERROR_UNEXPECTED;
     681             :     }
     682           0 : 
     683           0 :     nsConnectionEntry *ent = mCT.GetWeak(conn->ConnectionInfo()->HashKey());
     684           0 : 
     685             :     if (!ent || !ent->mIdleConns.RemoveElement(conn)) {
     686             :         return NS_ERROR_UNEXPECTED;
     687             :     }
     688           0 : 
     689             :     mNumIdleConns--;
     690             :     ConditionallyStopPruneDeadConnectionsTimer();
     691             :     return NS_OK;
     692           0 : }
     693           0 : 
     694           0 : nsHttpConnection *
     695             : nsHttpConnectionMgr::FindCoalescableConnectionByHashKey(nsConnectionEntry *ent,
     696           0 :                                                         const nsCString &key,
     697           0 :                                                         bool justKidding)
     698             : {
     699             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
     700             :     MOZ_ASSERT(ent->mConnInfo);
     701           0 :     nsHttpConnectionInfo *ci = ent->mConnInfo;
     702           0 : 
     703             :     nsTArray<nsWeakPtr> *listOfWeakConns =  mCoalescingHash.Get(key);
     704           0 :     if (!listOfWeakConns) {
     705           0 :         return nullptr;
     706             :     }
     707           0 : 
     708             :     uint32_t listLen = listOfWeakConns->Length();
     709           0 :     for (uint32_t j = 0; j < listLen; ) {
     710           0 : 
     711             :         RefPtr<nsHttpConnection> potentialMatch = do_QueryReferent(listOfWeakConns->ElementAt(j));
     712           0 :         if (!potentialMatch) {
     713           0 :             // This is a connection that needs to be removed from the list
     714           0 :             LOG(("FindCoalescableConnectionByHashKey() found old conn %p that has null weak ptr - removing\n",
     715           0 :                  listOfWeakConns->ElementAt(j).get()));
     716             :             if (j != listLen - 1) {
     717             :                 listOfWeakConns->Elements()[j] = listOfWeakConns->Elements()[listLen - 1];
     718             :             }
     719           0 :             listOfWeakConns->RemoveElementAt(listLen - 1);
     720           0 :             MOZ_ASSERT(listOfWeakConns->Length() == listLen - 1);
     721             :             listLen--;
     722           0 :             continue; // without adjusting iterator
     723             :         }
     724           0 : 
     725           0 :         bool couldJoin;
     726             :         if (justKidding) {
     727           0 :             couldJoin = potentialMatch->TestJoinConnection(ci->GetOrigin(), ci->OriginPort());
     728             :         } else {
     729           0 :             couldJoin = potentialMatch->JoinConnection(ci->GetOrigin(), ci->OriginPort());
     730             :         }
     731             :         if (couldJoin) {
     732           0 :             LOG(("FindCoalescableConnectionByHashKey() found match conn=%p key=%s newCI=%s matchedCI=%s join ok\n",
     733             :                  potentialMatch.get(), key.get(), ci->HashKey().get(), potentialMatch->ConnectionInfo()->HashKey().get()));
     734             :             return potentialMatch.get();
     735           0 :         }
     736           0 :         LOG(("FindCoalescableConnectionByHashKey() found match conn=%p key=%s newCI=%s matchedCI=%s join failed\n",
     737           0 :              potentialMatch.get(), key.get(), ci->HashKey().get(), potentialMatch->ConnectionInfo()->HashKey().get()));
     738             : 
     739             :         ++j; // bypassed by continue when weakptr fails
     740             :     }
     741             : 
     742             :     if (!listLen) { // shrunk to 0 while iterating
     743           0 :         LOG(("FindCoalescableConnectionByHashKey() removing empty list element\n"));
     744             :         mCoalescingHash.Remove(key);
     745             :     }
     746           0 :     return nullptr;
     747           0 : }
     748           0 : 
     749             : static void
     750           0 : BuildOriginFrameHashKey(nsACString &newKey, nsHttpConnectionInfo *ci,
     751             :                         const nsACString &host, int32_t port)
     752           0 : {
     753           0 :     newKey.Assign(host);
     754           0 :     if (ci->GetAnonymous()) {
     755           0 :         newKey.AppendLiteral("~A:");
     756           0 :     } else {
     757           0 :         newKey.AppendLiteral("~.:");
     758           0 :     }
     759             :     newKey.AppendInt(port);
     760             :     newKey.AppendLiteral("/[");
     761           0 :     nsAutoCString suffix;
     762             :     ci->GetOriginAttributes().CreateSuffix(suffix);
     763             :     newKey.Append(suffix);
     764           0 :     newKey.AppendLiteral("]viaORIGIN.FRAME");
     765           0 : }
     766           0 : 
     767           0 : nsHttpConnection *
     768             : nsHttpConnectionMgr::FindCoalescableConnection(nsConnectionEntry *ent,
     769           0 :                                                bool justKidding)
     770           0 : {
     771             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
     772           0 :     MOZ_ASSERT(ent->mConnInfo);
     773           0 :     nsHttpConnectionInfo *ci = ent->mConnInfo;
     774           0 :     LOG(("FindCoalescableConnection %s\n", ci->HashKey().get()));
     775             :     // First try and look it up by origin frame
     776             :     nsCString newKey;
     777             :     BuildOriginFrameHashKey(newKey, ci, ci->GetOrigin(), ci->OriginPort());
     778             :     nsHttpConnection *conn =
     779             :         FindCoalescableConnectionByHashKey(ent, newKey, justKidding);
     780             :     if (conn) {
     781           0 :         LOG(("FindCoalescableConnection(%s) match conn %p on frame key %s\n",
     782           0 :              ci->HashKey().get(), conn, newKey.get()));
     783           0 :         return conn;
     784           0 :     }
     785           0 : 
     786             :     // now check for DNS based keys
     787             :     // deleted conns (null weak pointers) are removed from list
     788             :     uint32_t keyLen = ent->mCoalescingKeys.Length();
     789             :     for (uint32_t i = 0; i < keyLen; ++i) {
     790             :         conn = FindCoalescableConnectionByHashKey(ent, ent->mCoalescingKeys[i], justKidding);
     791           0 :         if (conn) {
     792             :             LOG(("FindCoalescableConnection(%s) match conn %p on dns key %s\n",
     793             :                  ci->HashKey().get(), conn, ent->mCoalescingKeys[i].get()));
     794             :             return conn;
     795             :         }
     796           0 :     }
     797             : 
     798             :     LOG(("FindCoalescableConnection(%s) no matching conn\n", ci->HashKey().get()));
     799           0 :     return nullptr;
     800           0 : }
     801           0 : 
     802           0 : void
     803           0 : nsHttpConnectionMgr::UpdateCoalescingForNewConn(nsHttpConnection *newConn,
     804             :                                                 nsConnectionEntry *ent)
     805           0 : {
     806           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
     807           0 :     MOZ_ASSERT(newConn);
     808             :     MOZ_ASSERT(newConn->ConnectionInfo());
     809           0 :     MOZ_ASSERT(ent);
     810           0 :     MOZ_ASSERT(mCT.GetWeak(newConn->ConnectionInfo()->HashKey()) == ent);
     811             : 
     812             :     nsHttpConnection *existingConn = FindCoalescableConnection(ent, true);
     813             :     if (existingConn) {
     814             :         LOG(("UpdateCoalescingForNewConn() found existing active conn that could have served newConn "
     815           0 :              "graceful close of newConn=%p to migrate to existingConn %p\n", newConn, existingConn));
     816             :         newConn->DontReuse();
     817             :         return;
     818             :     }
     819           0 : 
     820           0 :     // This connection might go into the mCoalescingHash for new transactions to be coalesced onto
     821           0 :     // if it can accept new transactions
     822             :     if (!newConn->CanDirectlyActivate()) {
     823           0 :         return;
     824           0 :     }
     825           0 : 
     826           0 :     uint32_t keyLen = ent->mCoalescingKeys.Length();
     827           0 :     for (uint32_t i = 0;i < keyLen; ++i) {
     828             :         LOG(("UpdateCoalescingForNewConn() registering newConn %p %s under key %s\n",
     829           0 :              newConn, newConn->ConnectionInfo()->HashKey().get(), ent->mCoalescingKeys[i].get()));
     830           0 :         nsTArray<nsWeakPtr> *listOfWeakConns =  mCoalescingHash.Get(ent->mCoalescingKeys[i]);
     831             :         if (!listOfWeakConns) {
     832             :             LOG(("UpdateCoalescingForNewConn() need new list element\n"));
     833             :             listOfWeakConns = new nsTArray<nsWeakPtr>(1);
     834             :             mCoalescingHash.Put(ent->mCoalescingKeys[i], listOfWeakConns);
     835           0 :         }
     836           0 :         listOfWeakConns->AppendElement(
     837           0 :             do_GetWeakReference(static_cast<nsISupportsWeakReference*>(newConn)));
     838             :     }
     839           0 : 
     840             :     // Cancel any other pending connections - their associated transactions
     841             :     // are in the pending queue and will be dispatched onto this new connection
     842           0 :     for (int32_t index = ent->mHalfOpens.Length() - 1; index >= 0; --index) {
     843             :         RefPtr<nsHalfOpenSocket> half = ent->mHalfOpens[index];
     844             :         LOG(("UpdateCoalescingForNewConn() forcing halfopen abandon %p\n",
     845             :              half.get()));
     846             :         ent->mHalfOpens[index]->Abandon();
     847             :     }
     848             : 
     849           0 :     if (ent->mActiveConns.Length() > 1) {
     850           0 :         // this is a new connection that can be coalesced onto. hooray!
     851           0 :         // if there are other connection to this entry (e.g.
     852           0 :         // some could still be handshaking, shutting down, etc..) then close
     853             :         // them down after any transactions that are on them are complete.
     854           0 :         // This probably happened due to the parallel connection algorithm
     855             :         // that is used only before the host is known to speak h2.
     856             :         for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
     857             :             nsHttpConnection *otherConn = ent->mActiveConns[index];
     858             :             if (otherConn != newConn) {
     859           0 :                 LOG(("UpdateCoalescingForNewConn() shutting down old connection (%p) because new "
     860           0 :                      "spdy connection (%p) takes precedence\n", otherConn, newConn));
     861             :                 otherConn->DontReuse();
     862             :             }
     863           0 :         }
     864           0 :     }
     865             : 
     866             :     for (int32_t index = ent->mHalfOpenFastOpenBackups.Length() - 1; index >= 0; --index) {
     867             :         LOG(("UpdateCoalescingForNewConn() shutting down connection in fast "
     868             :              "open state (%p) because new spdy connection (%p) takes "
     869             :              "precedence\n", ent->mHalfOpenFastOpenBackups[index].get(), newConn));
     870             :         RefPtr<nsHalfOpenSocket> half = ent->mHalfOpenFastOpenBackups[index];
     871             :         half->CancelFastOpenConnection();
     872             :     }
     873             : }
     874             : 
     875             : // This function lets a connection, after completing the NPN phase,
     876           0 : // report whether or not it is using spdy through the usingSpdy
     877             : // argument. It would not be necessary if NPN were driven out of
     878             : // the connection manager. The connection entry associated with the
     879           0 : // connection is then updated to indicate whether or not we want to use
     880           0 : // spdy with that host and update the coalescing hash
     881             : // entries used for de-sharding hostsnames.
     882             : void
     883           0 : nsHttpConnectionMgr::ReportSpdyConnection(nsHttpConnection *conn,
     884           0 :                                           bool usingSpdy)
     885             : {
     886             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
     887             :     if (!conn->ConnectionInfo()) {
     888           0 :         return;
     889           0 :     }
     890             :     nsConnectionEntry *ent = mCT.GetWeak(conn->ConnectionInfo()->HashKey());
     891             :     if (!ent || !usingSpdy) {
     892           0 :         return;
     893           0 :     }
     894           0 : 
     895           0 :     ent->mUsingSpdy = true;
     896             :     mNumSpdyActiveConns++;
     897             : 
     898           0 :     // adjust timeout timer
     899             :     uint32_t ttl = conn->TimeToLive();
     900           0 :     uint64_t timeOfExpire = NowInSeconds() + ttl;
     901           0 :     if (!mTimer || timeOfExpire < mTimeOfNextWakeUp) {
     902           0 :         PruneDeadConnectionsAfter(ttl);
     903             :     }
     904             : 
     905             :     UpdateCoalescingForNewConn(conn, ent);
     906           0 : 
     907           0 :     nsresult rv = ProcessPendingQ(ent->mConnInfo);
     908           0 :     if (NS_FAILED(rv)) {
     909             :         LOG(("ReportSpdyConnection conn=%p ent=%p "
     910             :              "failed to process pending queue (%08x)\n", conn, ent,
     911             :              static_cast<uint32_t>(rv)));
     912             :     }
     913             :     rv = PostEvent(&nsHttpConnectionMgr::OnMsgProcessAllSpdyPendingQ);
     914             :     if (NS_FAILED(rv)) {
     915             :         LOG(("ReportSpdyConnection conn=%p ent=%p "
     916           0 :              "failed to post event (%08x)\n", conn, ent,
     917             :              static_cast<uint32_t>(rv)));
     918             :     }
     919             : }
     920           0 : 
     921             : //-----------------------------------------------------------------------------
     922           0 : bool
     923             : nsHttpConnectionMgr::DispatchPendingQ(nsTArray<RefPtr<nsHttpConnectionMgr::PendingTransactionInfo> > &pendingQ,
     924           0 :                                       nsConnectionEntry *ent,
     925             :                                       bool considerAll)
     926             : {
     927             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
     928             : 
     929           0 :     PendingTransactionInfo *pendingTransInfo = nullptr;
     930           0 :     nsresult rv;
     931           0 :     bool dispatchedSuccessfully = false;
     932             : 
     933             :     // if !considerAll iterate the pending list until one is dispatched successfully.
     934             :     // Keep iterating afterwards only until a transaction fails to dispatch.
     935             :     // if considerAll == true then try and dispatch all items.
     936             :     for (uint32_t i = 0; i < pendingQ.Length(); ) {
     937             :         pendingTransInfo = pendingQ[i];
     938             :         LOG(("nsHttpConnectionMgr::DispatchPendingQ "
     939             :              "[trans=%p, halfOpen=%p, activeConn=%p]\n",
     940             :              pendingTransInfo->mTransaction.get(),
     941             :              pendingTransInfo->mHalfOpen.get(),
     942           0 :              pendingTransInfo->mActiveConn.get()));
     943           0 : 
     944           0 :         // When this transaction has already established a half-open
     945             :         // connection, we want to prevent any duplicate half-open
     946           0 :         // connections from being established and bound to this
     947           0 :         // transaction. Allow only use of an idle persistent connection
     948             :         // (if found) for transactions referred by a half-open connection.
     949             :         bool alreadyHalfOpenOrWaitingForTLS = false;
     950           0 :         if (pendingTransInfo->mHalfOpen) {
     951             :             MOZ_ASSERT(!pendingTransInfo->mActiveConn);
     952             :             RefPtr<nsHalfOpenSocket> halfOpen =
     953             :                 do_QueryReferent(pendingTransInfo->mHalfOpen);
     954           0 :             LOG(("nsHttpConnectionMgr::DispatchPendingQ "
     955             :                  "[trans=%p, halfOpen=%p]\n",
     956           0 :                  pendingTransInfo->mTransaction.get(), halfOpen.get()));
     957           0 :             if (halfOpen) {
     958             :                 alreadyHalfOpenOrWaitingForTLS = true;
     959           0 :             } else {
     960           0 :                 // If we have not found the halfOpen socket, remove the pointer.
     961             :                 pendingTransInfo->mHalfOpen = nullptr;
     962             :             }
     963             :         }  else if (pendingTransInfo->mActiveConn) {
     964             :             MOZ_ASSERT(!pendingTransInfo->mHalfOpen);
     965             :             RefPtr<nsHttpConnection> activeConn =
     966             :                 do_QueryReferent(pendingTransInfo->mActiveConn);
     967             :             LOG(("nsHttpConnectionMgr::DispatchPendingQ "
     968             :                  "[trans=%p, activeConn=%p]\n",
     969             :                  pendingTransInfo->mTransaction.get(), activeConn.get()));
     970           0 :             // Check if this transaction claimed a connection that is still
     971           0 :             // performing tls handshake with a NullHttpTransaction or it is between
     972           0 :             // finishing tls and reclaiming (When nullTrans finishes tls handshake,
     973           0 :             // httpConnection does not have a transaction any more and a
     974             :             // ReclaimConnection is dispatched). But if an error occurred the
     975             :             // connection will be closed, it will exist but CanReused will be
     976             :             // false.
     977           0 :             if (activeConn &&
     978             :                 ((activeConn->Transaction() &&
     979             :                   activeConn->Transaction()->IsNullTransaction()) ||
     980             :                  (!activeConn->Transaction() && activeConn->CanReuse()))) {
     981           0 :                 alreadyHalfOpenOrWaitingForTLS = true;
     982           0 :             } else {
     983           0 :                 // If we have not found the connection, remove the pointer.
     984           0 :                 pendingTransInfo->mActiveConn = nullptr;
     985           0 :             }
     986           0 :         }
     987             : 
     988           0 :         rv = TryDispatchTransaction(ent,
     989             :                                     alreadyHalfOpenOrWaitingForTLS || !!pendingTransInfo->mTransaction->TunnelProvider(),
     990             :                                     pendingTransInfo);
     991             :         if (NS_SUCCEEDED(rv) || (rv != NS_ERROR_NOT_AVAILABLE)) {
     992           0 :             if (NS_SUCCEEDED(rv)) {
     993           0 :                 LOG(("  dispatching pending transaction...\n"));
     994             :             } else {
     995             :                 LOG(("  removing pending transaction based on "
     996             :                      "TryDispatchTransaction returning hard error %" PRIx32 "\n",
     997             :                      static_cast<uint32_t>(rv)));
     998             :             }
     999           0 :             ReleaseClaimedSockets(ent, pendingTransInfo);
    1000             :             if (pendingQ.RemoveElement(pendingTransInfo)) {
    1001             :                 // pendingTransInfo is now potentially destroyed
    1002           0 :                 dispatchedSuccessfully = true;
    1003             :                 continue; // dont ++i as we just made the array shorter
    1004             :             }
    1005           0 : 
    1006             :             LOG(("  transaction not found in pending queue\n"));
    1007             :         }
    1008           0 : 
    1009             :         if (dispatchedSuccessfully && !considerAll)
    1010             :             break;
    1011             : 
    1012           0 :         ++i;
    1013             : 
    1014             :     }
    1015             :     return dispatchedSuccessfully;
    1016             : }
    1017             : 
    1018             : uint32_t
    1019           0 : nsHttpConnectionMgr::TotalActiveConnections(nsConnectionEntry *ent) const
    1020             : {
    1021             :     // Add in the in-progress tcp connections, we will assume they are
    1022             :     // keepalive enabled.
    1023           0 :     // Exclude half-open's that has already created a usable connection.
    1024             :     // This prevents the limit being stuck on ipv6 connections that
    1025           0 :     // eventually time out after typical 21 seconds of no ACK+SYN reply.
    1026           0 :     return ent->mActiveConns.Length() + ent->UnconnectedHalfOpens();
    1027             : }
    1028             : 
    1029           0 : uint32_t
    1030             : nsHttpConnectionMgr::MaxPersistConnections(nsConnectionEntry *ent) const
    1031             : {
    1032             :     if (ent->mConnInfo->UsingHttpProxy() && !ent->mConnInfo->UsingConnect()) {
    1033           0 :         return static_cast<uint32_t>(mMaxPersistConnsPerProxy);
    1034             :     }
    1035             : 
    1036             :     return static_cast<uint32_t>(mMaxPersistConnsPerHost);
    1037             : }
    1038           0 : 
    1039             : void
    1040           0 : nsHttpConnectionMgr::PreparePendingQForDispatching(
    1041             :                             nsConnectionEntry *ent,
    1042           0 :                             nsTArray<RefPtr<PendingTransactionInfo>> &pendingQ,
    1043           0 :                             bool considerAll)
    1044             : {
    1045           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    1046           0 : 
    1047             :     pendingQ.Clear();
    1048             : 
    1049           0 :     uint32_t totalCount = TotalActiveConnections(ent);
    1050           0 :     uint32_t maxPersistConns = MaxPersistConnections(ent);
    1051             :     uint32_t availableConnections = maxPersistConns > totalCount
    1052             :         ? maxPersistConns - totalCount
    1053             :         : 0;
    1054           0 : 
    1055           0 :     // No need to try dispatching if we reach the active connection limit.
    1056           0 :     if (!availableConnections) {
    1057             :         return;
    1058             :     }
    1059             : 
    1060           0 :     // Only have to get transactions from the queue whose window id is 0.
    1061           0 :     if (!gHttpHandler->ActiveTabPriority()) {
    1062             :         ent->AppendPendingQForFocusedWindow(0, pendingQ, availableConnections);
    1063           0 :         return;
    1064           0 :     }
    1065             : 
    1066             :     uint32_t maxFocusedWindowConnections =
    1067             :         availableConnections * gHttpHandler->FocusedWindowTransactionRatio();
    1068             :     MOZ_ASSERT(maxFocusedWindowConnections < availableConnections);
    1069           0 : 
    1070           0 :     if (!maxFocusedWindowConnections) {
    1071             :         maxFocusedWindowConnections = 1;
    1072             :     }
    1073           0 : 
    1074             :     // Only need to dispatch transactions for either focused or
    1075           0 :     // non-focused window because considerAll is false.
    1076           0 :     if (!considerAll) {
    1077             :         ent->AppendPendingQForFocusedWindow(
    1078             :             mCurrentTopLevelOuterContentWindowId,
    1079           0 :             pendingQ,
    1080             :             maxFocusedWindowConnections);
    1081             : 
    1082             :         if (pendingQ.IsEmpty()) {
    1083             :             ent->AppendPendingQForNonFocusedWindows(
    1084             :                 mCurrentTopLevelOuterContentWindowId,
    1085           0 :                 pendingQ,
    1086           0 :                 availableConnections);
    1087             :         }
    1088           0 :         return;
    1089             :     }
    1090             : 
    1091           0 :     uint32_t maxNonFocusedWindowConnections =
    1092             :         availableConnections - maxFocusedWindowConnections;
    1093           0 :     nsTArray<RefPtr<PendingTransactionInfo>> remainingPendingQ;
    1094           0 : 
    1095             :     ent->AppendPendingQForFocusedWindow(
    1096             :         mCurrentTopLevelOuterContentWindowId,
    1097           0 :         pendingQ,
    1098             :         maxFocusedWindowConnections);
    1099             : 
    1100             :     if (maxNonFocusedWindowConnections) {
    1101             :         ent->AppendPendingQForNonFocusedWindows(
    1102             :             mCurrentTopLevelOuterContentWindowId,
    1103           0 :             remainingPendingQ,
    1104           0 :             maxNonFocusedWindowConnections);
    1105             :     }
    1106             : 
    1107           0 :     // If the slots for either focused or non-focused window are not filled up
    1108           0 :     // to the availability, try to use the remaining available connections
    1109           0 :     // for the other slot (with preference for the focused window).
    1110             :     if (remainingPendingQ.Length() < maxNonFocusedWindowConnections) {
    1111             :         ent->AppendPendingQForFocusedWindow(
    1112           0 :             mCurrentTopLevelOuterContentWindowId,
    1113             :             pendingQ,
    1114             :             maxNonFocusedWindowConnections - remainingPendingQ.Length());
    1115           0 :     } else if (pendingQ.Length() < maxFocusedWindowConnections) {
    1116             :         ent->AppendPendingQForNonFocusedWindows(
    1117             :             mCurrentTopLevelOuterContentWindowId,
    1118           0 :             remainingPendingQ,
    1119             :             maxFocusedWindowConnections - pendingQ.Length());
    1120             :     }
    1121             : 
    1122             :     MOZ_ASSERT(pendingQ.Length() + remainingPendingQ.Length() <=
    1123             :                availableConnections);
    1124             : 
    1125           0 :     LOG(("nsHttpConnectionMgr::PreparePendingQForDispatching "
    1126             :          "focused window pendingQ.Length()=%zu"
    1127             :          ", remainingPendingQ.Length()=%zu\n",
    1128             :          pendingQ.Length(), remainingPendingQ.Length()));
    1129           0 : 
    1130             :     // Append elements in |remainingPendingQ| to |pendingQ|. The order in
    1131           0 :     // |pendingQ| is like: [focusedWindowTrans...nonFocusedWindowTrans].
    1132             :     pendingQ.AppendElements(std::move(remainingPendingQ));
    1133           0 : }
    1134             : 
    1135             : bool
    1136             : nsHttpConnectionMgr::ProcessPendingQForEntry(nsConnectionEntry *ent, bool considerAll)
    1137             : {
    1138             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    1139             : 
    1140           0 :     LOG(("nsHttpConnectionMgr::ProcessPendingQForEntry "
    1141           0 :          "[ci=%s ent=%p active=%zu idle=%zu urgent-start-queue=%zu"
    1142           0 :          " queued=%zu]\n",
    1143           0 :          ent->mConnInfo->HashKey().get(), ent, ent->mActiveConns.Length(),
    1144             :          ent->mIdleConns.Length(), ent->mUrgentStartQ.Length(),
    1145           0 :          ent->PendingQLength()));
    1146           0 : 
    1147           0 :     if (LOG_ENABLED()) {
    1148           0 :       LOG(("urgent queue ["));
    1149             :       for (const auto& info : ent->mUrgentStartQ) {
    1150             :         LOG(("  %p", info->mTransaction.get()));
    1151           0 :       }
    1152           0 :       for (auto it = ent->mPendingTransactionTable.Iter(); !it.Done(); it.Next()) {
    1153           0 :         LOG(("] window id = %" PRIx64 " queue [", it.Key()));
    1154           0 :         for (const auto& info : *it.UserData()) {
    1155             :           LOG(("  %p", info->mTransaction.get()));
    1156             :         }
    1157           0 :       }
    1158           0 :       LOG(("] active urgent conns ["));
    1159           0 :       for (nsHttpConnection* conn : ent->mActiveConns) {
    1160           0 :         if (conn->IsUrgentStartPreferred()) {
    1161             :           LOG(("  %p", conn));
    1162             :         }
    1163           0 :       }
    1164           0 :       LOG(("] active regular conns ["));
    1165           0 :       for (nsHttpConnection* conn : ent->mActiveConns) {
    1166           0 :         if (!conn->IsUrgentStartPreferred()) {
    1167             :           LOG(("  %p", conn));
    1168             :         }
    1169           0 :       }
    1170           0 :       LOG(("] idle urgent conns ["));
    1171           0 :       for (nsHttpConnection* conn : ent->mIdleConns) {
    1172           0 :         if (conn->IsUrgentStartPreferred()) {
    1173             :           LOG(("  %p", conn));
    1174             :         }
    1175           0 :       }
    1176             :       LOG(("] idle regular conns ["));
    1177             :       for (nsHttpConnection* conn : ent->mIdleConns) {
    1178           0 :         if (!conn->IsUrgentStartPreferred()) {
    1179             :           LOG(("  %p", conn));
    1180             :         }
    1181           0 :       }
    1182             :       LOG(("]"));
    1183           0 :     }
    1184             : 
    1185           0 :     if (!ent->mUrgentStartQ.Length() && !ent->PendingQLength()) {
    1186           0 :         return false;
    1187             :     }
    1188           0 :     ProcessSpdyPendingQ(ent);
    1189             : 
    1190             :     bool dispatchedSuccessfully = false;
    1191           0 : 
    1192             :     if (!ent->mUrgentStartQ.IsEmpty()) {
    1193             :         dispatchedSuccessfully = DispatchPendingQ(ent->mUrgentStartQ,
    1194             :                                                   ent,
    1195           0 :                                                   considerAll);
    1196           0 :     }
    1197             : 
    1198             :     if (dispatchedSuccessfully && !considerAll) {
    1199             :         return dispatchedSuccessfully;
    1200           0 :     }
    1201             : 
    1202             :     nsTArray<RefPtr<PendingTransactionInfo>> pendingQ;
    1203             :     PreparePendingQForDispatching(ent, pendingQ, considerAll);
    1204           0 : 
    1205           0 :     // The only case that |pendingQ| is empty is when there is no
    1206             :     // connection available for dispatching.
    1207             :     if (pendingQ.IsEmpty()) {
    1208             :         return dispatchedSuccessfully;
    1209           0 :     }
    1210           0 : 
    1211             :     dispatchedSuccessfully |=
    1212             :         DispatchPendingQ(pendingQ, ent, considerAll);
    1213             : 
    1214           0 :     // Put the leftovers into connection entry, in the same order as they
    1215           0 :     // were before to keep the natural ordering.
    1216             :     for (const auto& transactionInfo : Reversed(pendingQ)) {
    1217             :         ent->InsertTransaction(transactionInfo, true);
    1218             :     }
    1219             : 
    1220             :     // Only remove empty pendingQ when considerAll is true.
    1221             :     if (considerAll) {
    1222           0 :         ent->RemoveEmptyPendingQ();
    1223             :     }
    1224           0 : 
    1225             :     return dispatchedSuccessfully;
    1226           0 : }
    1227           0 : 
    1228           0 : bool
    1229             : nsHttpConnectionMgr::ProcessPendingQForEntry(nsHttpConnectionInfo *ci)
    1230             : {
    1231             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    1232             : 
    1233             :     nsConnectionEntry *ent = mCT.GetWeak(ci->HashKey());
    1234             :     if (ent)
    1235             :         return ProcessPendingQForEntry(ent, false);
    1236             :     return false;
    1237           0 : }
    1238             : 
    1239           0 : // we're at the active connection limit if any one of the following conditions is true:
    1240           0 : //  (1) at max-connections
    1241           0 : //  (2) keep-alive enabled and at max-persistent-connections-per-server/proxy
    1242             : //  (3) keep-alive disabled and at max-connections-per-server
    1243           0 : bool
    1244             : nsHttpConnectionMgr::AtActiveConnectionLimit(nsConnectionEntry *ent, uint32_t caps)
    1245             : {
    1246             :     nsHttpConnectionInfo *ci = ent->mConnInfo;
    1247           0 :     uint32_t totalCount = TotalActiveConnections(ent);
    1248           0 :     uint32_t maxPersistConns = MaxPersistConnections(ent);
    1249           0 : 
    1250             :     LOG(("nsHttpConnectionMgr::AtActiveConnectionLimit [ci=%s caps=%x,"
    1251             :          "totalCount=%u, maxPersistConns=%u]\n",
    1252             :          ci->HashKey().get(), caps, totalCount, maxPersistConns));
    1253             : 
    1254             :     if (caps & NS_HTTP_URGENT_START) {
    1255             :         if (totalCount >= (mMaxUrgentExcessiveConns + maxPersistConns)) {
    1256             :             LOG(("The number of total connections are greater than or equal to sum of "
    1257             :                  "max urgent-start queue length and the number of max persistent connections.\n"));
    1258             :             return true;
    1259           0 :         }
    1260           0 :         return false;
    1261           0 :     }
    1262           0 : 
    1263             :     // update maxconns if potentially limited by the max socket count
    1264             :     // this requires a dynamic reduction in the max socket count to a point
    1265             :     // lower than the max-connections pref.
    1266             :     uint32_t maxSocketCount = gHttpHandler->MaxSocketCount();
    1267             :     if (mMaxConns > maxSocketCount) {
    1268           0 :         mMaxConns = maxSocketCount;
    1269           0 :         LOG(("nsHttpConnectionMgr %p mMaxConns dynamically reduced to %u",
    1270             :              this, mMaxConns));
    1271             :     }
    1272             : 
    1273           0 :     // If there are more active connections than the global limit, then we're
    1274           0 :     // done. Purging idle connections won't get us below it.
    1275             :     if (mNumActiveConns >= mMaxConns) {
    1276             :         LOG(("  num active conns == max conns\n"));
    1277             :         return true;
    1278             :     }
    1279           0 : 
    1280             :     bool result = (totalCount >= maxPersistConns);
    1281           0 :     LOG(("AtActiveConnectionLimit result: %s", result ? "true" : "false"));
    1282             :     return result;
    1283           0 : }
    1284           0 : 
    1285           0 : void
    1286           0 : nsHttpConnectionMgr::ClosePersistentConnections(nsConnectionEntry *ent)
    1287           0 : {
    1288             :     LOG(("nsHttpConnectionMgr::ClosePersistentConnections [ci=%s]\n",
    1289             :          ent->mConnInfo->HashKey().get()));
    1290           0 :     while (ent->mIdleConns.Length()) {
    1291           0 :         RefPtr<nsHttpConnection> conn(ent->mIdleConns[0]);
    1292           0 :         ent->mIdleConns.RemoveElementAt(0);
    1293           0 :         mNumIdleConns--;
    1294           0 :         conn->Close(NS_ERROR_ABORT);
    1295           0 :     }
    1296             : 
    1297           0 :     int32_t activeCount = ent->mActiveConns.Length();
    1298             :     for (int32_t i=0; i < activeCount; i++)
    1299             :         ent->mActiveConns[i]->DontReuse();
    1300           0 :     for (int32_t index = ent->mHalfOpenFastOpenBackups.Length() - 1; index >= 0; --index) {
    1301             :         RefPtr<nsHalfOpenSocket> half = ent->mHalfOpenFastOpenBackups[index];
    1302           0 :         half->CancelFastOpenConnection();
    1303             :     }
    1304           0 : }
    1305             : 
    1306             : bool
    1307             : nsHttpConnectionMgr::RestrictConnections(nsConnectionEntry *ent)
    1308           0 : {
    1309             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    1310             : 
    1311             :     if (ent->AvailableForDispatchNow()) {
    1312             :         // this might be a h2/spdy connection in this connection entry that
    1313             :         // is able to be immediately muxxed, or it might be one that
    1314             :         // was found in the same state through a coalescing hash
    1315             :         LOG(("nsHttpConnectionMgr::RestrictConnections %p %s restricted due to active >=h2\n",
    1316             :              ent, ent->mConnInfo->HashKey().get()));
    1317             :         return true;
    1318           0 :     }
    1319           0 : 
    1320             :     // If this host is trying to negotiate a SPDY session right now,
    1321             :     // don't create any new ssl connections until the result of the
    1322           0 :     // negotiation is known.
    1323             : 
    1324             :     bool doRestrict =
    1325             :         ent->mConnInfo->FirstHopSSL() && gHttpHandler->IsSpdyEnabled() &&
    1326             :         ent->mUsingSpdy && (ent->mHalfOpens.Length() || ent->mActiveConns.Length());
    1327           0 : 
    1328             :     // If there are no restrictions, we are done
    1329             :     if (!doRestrict)
    1330             :         return false;
    1331             : 
    1332             :     // If the restriction is based on a tcp handshake in progress
    1333             :     // let that connect and then see if it was SPDY or not
    1334           0 :     if (ent->UnconnectedHalfOpens()) {
    1335             :         return true;
    1336           0 :     }
    1337           0 : 
    1338           0 :     // There is a concern that a host is using a mix of HTTP/1 and SPDY.
    1339             :     // In that case we don't want to restrict connections just because
    1340             :     // there is a single active HTTP/1 session in use.
    1341             :     if (ent->mUsingSpdy && ent->mActiveConns.Length()) {
    1342             :         bool confirmedRestrict = false;
    1343           0 :         for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
    1344           0 :             nsHttpConnection *conn = ent->mActiveConns[index];
    1345           0 :             if (!conn->ReportedNPN() || conn->CanDirectlyActivate()) {
    1346             :                 confirmedRestrict = true;
    1347             :                 break;
    1348             :             }
    1349             :         }
    1350             :         doRestrict = confirmedRestrict;
    1351             :         if (!confirmedRestrict) {
    1352             :             LOG(("nsHttpConnectionMgr spdy connection restriction to "
    1353             :                  "%s bypassed.\n", ent->mConnInfo->Origin()));
    1354             :         }
    1355             :     }
    1356             :     return doRestrict;
    1357           0 : }
    1358             : 
    1359             : // returns NS_OK if a connection was started
    1360           0 : // return NS_ERROR_NOT_AVAILABLE if a new connection cannot be made due to
    1361             : //        ephemeral limits
    1362           0 : // returns other NS_ERROR on hard failure conditions
    1363             : nsresult
    1364           0 : nsHttpConnectionMgr::MakeNewConnection(nsConnectionEntry *ent,
    1365             :                                        PendingTransactionInfo *pendingTransInfo)
    1366           0 : {
    1367           0 :     nsHttpTransaction *trans = pendingTransInfo->mTransaction;
    1368           0 : 
    1369           0 :     LOG(("nsHttpConnectionMgr::MakeNewConnection %p ent=%p trans=%p",
    1370             :          this, ent, trans));
    1371             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    1372             : 
    1373             :     uint32_t halfOpenLength = ent->mHalfOpens.Length();
    1374             :     for (uint32_t i = 0; i < halfOpenLength; i++) {
    1375           0 :         auto halfOpen = ent->mHalfOpens[i];
    1376             :         if (halfOpen->AcceptsTransaction(trans) && halfOpen->Claim()) {
    1377             :             // We've found a speculative connection or a connection that
    1378             :             // is free to be used in the half open list.
    1379           0 :             // A free to be used connection is a connection that was
    1380             :             // open for a concrete transaction, but that trunsaction
    1381             :             // ended up using another connection.
    1382           0 :             LOG(("nsHttpConnectionMgr::MakeNewConnection [ci = %s]\n"
    1383             :                  "Found a speculative or a free-to-use half open connection\n",
    1384             :                  ent->mConnInfo->HashKey().get()));
    1385             :             pendingTransInfo->mHalfOpen =
    1386             :                 do_GetWeakReference(static_cast<nsISupportsWeakReference*>(ent->mHalfOpens[i]));
    1387             :             // return OK because we have essentially opened a new connection
    1388           0 :             // by converting a speculative half-open to general use
    1389           0 :             return NS_OK;
    1390           0 :         }
    1391           0 :     }
    1392           0 : 
    1393           0 :     // consider null transactions that are being used to drive the ssl handshake if
    1394           0 :     // the transaction creating this connection can re-use persistent connections
    1395             :     if (trans->Caps() & NS_HTTP_ALLOW_KEEPALIVE) {
    1396             :         uint32_t activeLength = ent->mActiveConns.Length();
    1397             :         for (uint32_t i = 0; i < activeLength; i++) {
    1398           0 :             nsAHttpTransaction *activeTrans = ent->mActiveConns[i]->Transaction();
    1399           0 :             NullHttpTransaction *nullTrans = activeTrans ? activeTrans->QueryNullTransaction() : nullptr;
    1400             :             if (nullTrans && nullTrans->Claim()) {
    1401             :                 LOG(("nsHttpConnectionMgr::MakeNewConnection [ci = %s] "
    1402             :                      "Claiming a null transaction for later use\n",
    1403             :                      ent->mConnInfo->HashKey().get()));
    1404             :                 pendingTransInfo->mActiveConn =
    1405             :                     do_GetWeakReference(static_cast<nsISupportsWeakReference*>(ent->mActiveConns[i]));
    1406             :                 return NS_OK;
    1407           0 :             }
    1408           0 :         }
    1409           0 :     }
    1410           0 : 
    1411             :     // If this host is trying to negotiate a SPDY session right now,
    1412             :     // don't create any new connections until the result of the
    1413             :     // negotiation is known.
    1414             :     if (!(trans->Caps() & NS_HTTP_DISALLOW_SPDY) &&
    1415             :         (trans->Caps() & NS_HTTP_ALLOW_KEEPALIVE) &&
    1416             :         RestrictConnections(ent)) {
    1417             :         LOG(("nsHttpConnectionMgr::MakeNewConnection [ci = %s] "
    1418             :              "Not Available Due to RestrictConnections()\n",
    1419             :              ent->mConnInfo->HashKey().get()));
    1420             :         return NS_ERROR_NOT_AVAILABLE;
    1421             :     }
    1422           0 : 
    1423             :     // We need to make a new connection. If that is going to exceed the
    1424             :     // global connection limit then try and free up some room by closing
    1425             :     // an idle connection to another host. We know it won't select "ent"
    1426           0 :     // because we have already determined there are no idle connections
    1427           0 :     // to our destination
    1428           0 : 
    1429           0 :     if ((mNumIdleConns + mNumActiveConns + 1 >= mMaxConns) && mNumIdleConns) {
    1430           0 :         // If the global number of connections is preventing the opening of new
    1431           0 :         // connections to a host without idle connections, then close them
    1432           0 :         // regardless of their TTL.
    1433             :         auto iter = mCT.Iter();
    1434           0 :         while (mNumIdleConns + mNumActiveConns + 1 >= mMaxConns &&
    1435           0 :                !iter.Done()) {
    1436           0 :             RefPtr<nsConnectionEntry> entry = iter.Data();
    1437           0 :             if (!entry->mIdleConns.Length()) {
    1438           0 :               iter.Next();
    1439             :               continue;
    1440             :             }
    1441             :             RefPtr<nsHttpConnection> conn(entry->mIdleConns[0]);
    1442           0 :             entry->mIdleConns.RemoveElementAt(0);
    1443           0 :             conn->Close(NS_ERROR_ABORT);
    1444             :             mNumIdleConns--;
    1445             :             ConditionallyStopPruneDeadConnectionsTimer();
    1446             :         }
    1447             :     }
    1448           0 : 
    1449           0 :     if ((mNumIdleConns + mNumActiveConns + 1 >= mMaxConns) &&
    1450           0 :         mNumActiveConns && gHttpHandler->IsSpdyEnabled())
    1451           0 :     {
    1452             :         // If the global number of connections is preventing the opening of new
    1453             :         // connections to a host without idle connections, then close any spdy
    1454           0 :         // ASAP.
    1455           0 :         for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
    1456             :             RefPtr<nsConnectionEntry> entry = iter.Data();
    1457           0 :             if (!entry->mUsingSpdy) {
    1458           0 :                 continue;
    1459           0 :             }
    1460             : 
    1461             :             for (uint32_t index = 0;
    1462           0 :                  index < entry->mActiveConns.Length();
    1463             :                  ++index) {
    1464             :                 nsHttpConnection *conn = entry->mActiveConns[index];
    1465             :                 if (conn->UsingSpdy() && conn->CanReuse()) {
    1466             :                     conn->DontReuse();
    1467             :                     // Stop on <= (particularly =) because this dontreuse
    1468             :                     // causes async close.
    1469             :                     if (mNumIdleConns + mNumActiveConns + 1 <= mMaxConns) {
    1470             :                         goto outerLoopEnd;
    1471             :                     }
    1472           0 :                 }
    1473             :             }
    1474             :         }
    1475           0 :       outerLoopEnd:
    1476           0 :         ;
    1477           0 :     }
    1478           0 : 
    1479             :     if (AtActiveConnectionLimit(ent, trans->Caps()))
    1480           0 :         return NS_ERROR_NOT_AVAILABLE;
    1481             : 
    1482             :     nsresult rv = CreateTransport(ent, trans, trans->Caps(), false, false,
    1483           0 :                                   trans->ClassOfService() & nsIClassOfService::UrgentStart,
    1484           0 :                                   true, pendingTransInfo);
    1485           0 :     if (NS_FAILED(rv)) {
    1486             :         /* hard failure */
    1487             :         LOG(("nsHttpConnectionMgr::MakeNewConnection [ci = %s trans = %p] "
    1488             :              "CreateTransport() hard failure.\n",
    1489             :              ent->mConnInfo->HashKey().get(), trans));
    1490             :         trans->Close(rv);
    1491             :         if (rv == NS_ERROR_NOT_AVAILABLE)
    1492             :             rv = NS_ERROR_FAILURE;
    1493             :         return rv;
    1494             :     }
    1495             : 
    1496             :     return NS_OK;
    1497             : }
    1498             : 
    1499           0 : // returns OK if a connection is found for the transaction
    1500             : //   and the transaction is started.
    1501             : // returns ERROR_NOT_AVAILABLE if no connection can be found and it
    1502             : //   should be queued until circumstances change
    1503           0 : // returns other ERROR when transaction has a hard failure and should
    1504             : //   not remain in the pending queue
    1505           0 : nsresult
    1506             : nsHttpConnectionMgr::TryDispatchTransaction(nsConnectionEntry *ent,
    1507           0 :                                             bool onlyReusedConnection,
    1508             :                                             PendingTransactionInfo *pendingTransInfo)
    1509             : {
    1510             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    1511             : 
    1512             :     nsHttpTransaction *trans = pendingTransInfo->mTransaction;
    1513             : 
    1514             :     LOG(("nsHttpConnectionMgr::TryDispatchTransaction without conn "
    1515             :          "[trans=%p halfOpen=%p conn=%p ci=%p ci=%s caps=%x tunnelprovider=%p "
    1516             :          "onlyreused=%d active=%zu idle=%zu]\n", trans,
    1517           0 :          pendingTransInfo->mHalfOpen.get(),
    1518             :          pendingTransInfo->mActiveConn.get(), ent->mConnInfo.get(),
    1519             :          ent->mConnInfo->HashKey().get(),
    1520             :          uint32_t(trans->Caps()), trans->TunnelProvider(),
    1521             :          onlyReusedConnection, ent->mActiveConns.Length(),
    1522             :          ent->mIdleConns.Length()));
    1523             : 
    1524             :     uint32_t caps = trans->Caps();
    1525             : 
    1526             :     // 0 - If this should use spdy then dispatch it post haste.
    1527             :     // 1 - If there is connection pressure then see if we can pipeline this on
    1528             :     //     a connection of a matching type instead of using a new conn
    1529             :     // 2 - If there is an idle connection, use it!
    1530             :     // 3 - if class == reval or script and there is an open conn of that type
    1531             :     //     then pipeline onto shortest pipeline of that class if limits allow
    1532             :     // 4 - If we aren't up against our connection limit,
    1533           0 :     //     then open a new one
    1534             :     // 5 - Try a pipeline if we haven't already - this will be unusual because
    1535             :     //     it implies a low connection pressure situation where
    1536             :     //     MakeNewConnection() failed.. that is possible, but unlikely, due to
    1537             :     //     global limits
    1538             :     // 6 - no connection is available - queue it
    1539           0 : 
    1540           0 :     RefPtr<nsHttpConnection> unusedSpdyPersistentConnection;
    1541           0 : 
    1542           0 :     // step 0
    1543           0 :     // look for existing spdy connection - that's always best because it is
    1544           0 :     // essentially pipelining without head of line blocking
    1545           0 : 
    1546           0 :     if (!(caps & NS_HTTP_DISALLOW_SPDY) && gHttpHandler->IsSpdyEnabled()) {
    1547             :         RefPtr<nsHttpConnection> conn = GetSpdyActiveConn(ent);
    1548             :         if (conn) {
    1549           0 :             if ((caps & NS_HTTP_ALLOW_KEEPALIVE) || !conn->IsExperienced()) {
    1550             :                 LOG(("   dispatch to spdy: [conn=%p]\n", conn.get()));
    1551             :                 trans->RemoveDispatchedAsBlocking();  /* just in case */
    1552             :                 nsresult rv = DispatchTransaction(ent, trans, conn);
    1553             :                 NS_ENSURE_SUCCESS(rv, rv);
    1554             :                 return NS_OK;
    1555             :             }
    1556             :             unusedSpdyPersistentConnection = conn;
    1557           0 :         }
    1558           0 :     }
    1559           0 : 
    1560           0 :     // If this is not a blocking transaction and the request context for it is
    1561           0 :     // currently processing one or more blocking transactions then we
    1562           0 :     // need to just leave it in the queue until those are complete unless it is
    1563           0 :     // explicitly marked as unblocked.
    1564             :     if (!(caps & NS_HTTP_LOAD_AS_BLOCKING)) {
    1565           0 :         if (!(caps & NS_HTTP_LOAD_UNBLOCKED)) {
    1566             :             nsIRequestContext *requestContext = trans->RequestContext();
    1567           0 :             if (requestContext) {
    1568             :                 uint32_t blockers = 0;
    1569             :                 if (NS_SUCCEEDED(requestContext->GetBlockingTransactionCount(&blockers)) &&
    1570             :                     blockers) {
    1571             :                     // need to wait for blockers to clear
    1572             :                     LOG(("   blocked by request context: [rc=%p trans=%p blockers=%d]\n",
    1573             :                          requestContext, trans, blockers));
    1574           0 :                     return NS_ERROR_NOT_AVAILABLE;
    1575             :                 }
    1576             :             }
    1577             :         }
    1578             :     } else {
    1579             :         // Mark the transaction and its load group as blocking right now to prevent
    1580             :         // other transactions from being reordered in the queue due to slow syns.
    1581             :         trans->DispatchedAsBlocking();
    1582             :     }
    1583             : 
    1584             :     // step 1
    1585             :     // If connection pressure, then we want to favor pipelining of any kind
    1586             :     // h1 pipelining has been removed
    1587             : 
    1588           0 :     // Subject most transactions at high parallelism to rate pacing.
    1589             :     // It will only be actually submitted to the
    1590             :     // token bucket once, and if possible it is granted admission synchronously.
    1591           0 :     // It is important to leave a transaction in the pending queue when blocked by
    1592           0 :     // pacing so it can be found on cancel if necessary.
    1593           0 :     // Transactions that cause blocking or bypass it (e.g. js/css) are not rate
    1594           0 :     // limited.
    1595             :     if (gHttpHandler->UseRequestTokenBucket()) {
    1596           0 :         // submit even whitelisted transactions to the token bucket though they will
    1597           0 :         // not be slowed by it
    1598             :         bool runNow = trans->TryToRunPacedRequest();
    1599             :         if (!runNow) {
    1600           0 :             if ((mNumActiveConns - mNumSpdyActiveConns) <=
    1601           0 :                 gHttpHandler->RequestTokenBucketMinParallelism()) {
    1602             :                 runNow = true; // white list it
    1603             :             } else if (caps & (NS_HTTP_LOAD_AS_BLOCKING | NS_HTTP_LOAD_UNBLOCKED)) {
    1604             :                 runNow = true; // white list it
    1605             :             }
    1606             :         }
    1607             :         if (!runNow) {
    1608           0 :             LOG(("   blocked due to rate pacing trans=%p\n", trans));
    1609           0 :             return NS_ERROR_NOT_AVAILABLE;
    1610             :         }
    1611           0 :     }
    1612           0 : 
    1613           0 :     // step 2
    1614             :     // consider an idle persistent connection
    1615             :     bool idleConnsAllUrgent = false;
    1616             :     if (caps & NS_HTTP_ALLOW_KEEPALIVE) {
    1617             :         nsresult rv = TryDispatchTransactionOnIdleConn(ent, pendingTransInfo,
    1618             :                                                        true, &idleConnsAllUrgent);
    1619             :         if (NS_SUCCEEDED(rv)) {
    1620             :             LOG(("   dispatched step 2 (idle) trans=%p\n", trans));
    1621             :             return NS_OK;
    1622             :         }
    1623           0 :     }
    1624           0 : 
    1625           0 :     // step 3
    1626             :     // consider pipelining scripts and revalidations
    1627           0 :     // h1 pipelining has been removed
    1628             : 
    1629             :     // step 4
    1630             :     if (!onlyReusedConnection) {
    1631           0 :         nsresult rv = MakeNewConnection(ent, pendingTransInfo);
    1632             :         if (NS_SUCCEEDED(rv)) {
    1633             :             // this function returns NOT_AVAILABLE for asynchronous connects
    1634           0 :             LOG(("   dispatched step 4 (async new conn) trans=%p\n", trans));
    1635             :             return NS_ERROR_NOT_AVAILABLE;
    1636             :         }
    1637             : 
    1638             :         if (rv != NS_ERROR_NOT_AVAILABLE) {
    1639             :             // not available return codes should try next step as they are
    1640             :             // not hard errors. Other codes should stop now
    1641             :             LOG(("   failed step 4 (%" PRIx32 ") trans=%p\n",
    1642             :                  static_cast<uint32_t>(rv), trans));
    1643           0 :             return rv;
    1644           0 :         }
    1645           0 : 
    1646             :         // repeat step 2 when there are only idle connections and all are urgent,
    1647           0 :         // don't respect urgency so that non-urgent transaction will be allowed
    1648           0 :         // to dispatch on an urgent-start-only marked connection to avoid
    1649           0 :         // dispatch deadlocks
    1650             :         if (!(trans->ClassOfService() & nsIClassOfService::UrgentStart) &&
    1651             :             idleConnsAllUrgent &&
    1652             :             ent->mActiveConns.Length() < MaxPersistConnections(ent))
    1653           0 :         {
    1654           0 :             rv = TryDispatchTransactionOnIdleConn(ent, pendingTransInfo, false);
    1655             :             if (NS_SUCCEEDED(rv)) {
    1656             :                 LOG(("   dispatched step 2a (idle, reuse urgent) trans=%p\n", trans));
    1657             :                 return NS_OK;
    1658             :             }
    1659             :         }
    1660             :     } else if (trans->TunnelProvider() && trans->TunnelProvider()->MaybeReTunnel(trans)) {
    1661             :         LOG(("   sort of dispatched step 4a tunnel requeue trans=%p\n", trans));
    1662             :         // the tunnel provider took responsibility for making a new tunnel
    1663           0 :         return NS_OK;
    1664             :     }
    1665             : 
    1666             :     // step 5
    1667           0 :     // previously pipelined anything here if allowed but h1 pipelining has been removed
    1668             : 
    1669             :     // step 6
    1670           0 :     if (unusedSpdyPersistentConnection) {
    1671             :         // to avoid deadlocks, we need to throw away this perfectly valid SPDY
    1672             :         // connection to make room for a new one that can service a no KEEPALIVE
    1673             :         // request
    1674             :         unusedSpdyPersistentConnection->DontReuse();
    1675           0 :     }
    1676             : 
    1677             :     LOG(("   not dispatched (queued) trans=%p\n", trans));
    1678             :     return NS_ERROR_NOT_AVAILABLE;                /* queue it */
    1679           0 : }
    1680             : 
    1681           0 : nsresult
    1682           0 : nsHttpConnectionMgr::TryDispatchTransactionOnIdleConn(
    1683             :     nsConnectionEntry * ent, PendingTransactionInfo * pendingTransInfo,
    1684           0 :     bool respectUrgency, bool *allUrgent)
    1685             : {
    1686             :     bool onlyUrgent = !!ent->mIdleConns.Length();
    1687           0 : 
    1688           0 :     nsHttpTransaction *trans = pendingTransInfo->mTransaction;
    1689           0 :     bool urgentTrans = trans->ClassOfService() & nsIClassOfService::UrgentStart;
    1690           0 : 
    1691             :     LOG(("nsHttpConnectionMgr::TryDispatchTransactionOnIdleConn, ent=%p, trans=%p, urgent=%d",
    1692             :          ent, trans, urgentTrans));
    1693             : 
    1694           0 :     RefPtr<nsHttpConnection> conn;
    1695           0 :     size_t index = 0;
    1696           0 :     while (!conn && (ent->mIdleConns.Length() > index)) {
    1697           0 :         conn = ent->mIdleConns[index];
    1698           0 : 
    1699             :         // non-urgent transactions can only be dispatched on non-urgent
    1700             :         // started or used connections.
    1701           0 :         if (respectUrgency && conn->IsUrgentStartPreferred() && !urgentTrans) {
    1702             :             LOG(("  skipping urgent: [conn=%p]", conn.get()));
    1703           0 :             conn = nullptr;
    1704           0 :             ++index;
    1705             :             continue;
    1706             :         }
    1707             : 
    1708           0 :         onlyUrgent = false;
    1709           0 : 
    1710           0 :         ent->mIdleConns.RemoveElementAt(index);
    1711           0 :         mNumIdleConns--;
    1712             : 
    1713             :         // we check if the connection can be reused before even checking if
    1714           0 :         // it is a "matching" connection.
    1715           0 :         if (!conn->CanReuse()) {
    1716             :             LOG(("   dropping stale connection: [conn=%p]\n", conn.get()));
    1717             :             conn->Close(NS_ERROR_ABORT);
    1718             :             conn = nullptr;
    1719             :         }
    1720           0 :         else {
    1721             :             LOG(("   reusing connection: [conn=%p]\n", conn.get()));
    1722             :             conn->EndIdleMonitoring();
    1723           0 :         }
    1724           0 : 
    1725             :         // If there are no idle connections left at all, we need to make
    1726             :         // sure that we are not pruning dead connections anymore.
    1727           0 :         ConditionallyStopPruneDeadConnectionsTimer();
    1728             :     }
    1729             : 
    1730           0 :     if (allUrgent) {
    1731           0 :         *allUrgent = onlyUrgent;
    1732           0 :     }
    1733             : 
    1734             :     if (conn) {
    1735             :         // This will update the class of the connection to be the class of
    1736             :         // the transaction dispatched on it.
    1737             :         AddActiveConn(conn, ent);
    1738             :         nsresult rv = DispatchTransaction(ent, trans, conn);
    1739             :         NS_ENSURE_SUCCESS(rv, rv);
    1740             : 
    1741           0 :         return NS_OK;
    1742             :     }
    1743             : 
    1744             :     return NS_ERROR_NOT_AVAILABLE;
    1745           0 : }
    1746           0 : 
    1747             : nsresult
    1748             : nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
    1749           0 :                                          nsHttpTransaction *trans,
    1750             :                                          nsHttpConnection *conn)
    1751             : {
    1752             :     uint32_t caps = trans->Caps();
    1753             :     int32_t priority = trans->Priority();
    1754             :     nsresult rv;
    1755             : 
    1756           0 :     LOG(("nsHttpConnectionMgr::DispatchTransaction "
    1757             :          "[ent-ci=%s %p trans=%p caps=%x conn=%p priority=%d]\n",
    1758           0 :          ent->mConnInfo->HashKey().get(), ent, trans, caps, conn, priority));
    1759           0 : 
    1760             :     // It is possible for a rate-paced transaction to be dispatched independent
    1761             :     // of the token bucket when the amount of parallelization has changed or
    1762             :     // when a muxed connection (e.g. h2) becomes available.
    1763           0 :     trans->CancelPacing(NS_OK);
    1764           0 : 
    1765           0 :     if (conn->UsingSpdy()) {
    1766           0 :         LOG(("Spdy Dispatch Transaction via Activate(). Transaction host = %s, "
    1767           0 :              "Connection host = %s\n",
    1768             :              trans->ConnectionInfo()->Origin(),
    1769             :              conn->ConnectionInfo()->Origin()));
    1770             :         rv = conn->Activate(trans, caps, priority);
    1771             :         MOZ_ASSERT(NS_SUCCEEDED(rv), "SPDY Cannot Fail Dispatch");
    1772             :         if (NS_SUCCEEDED(rv) && !trans->GetPendingTime().IsNull()) {
    1773           0 :             AccumulateTimeDelta(Telemetry::TRANSACTION_WAIT_TIME_SPDY,
    1774             :                 trans->GetPendingTime(), TimeStamp::Now());
    1775             :             trans->SetPendingTime(false);
    1776           0 :         }
    1777             :         return rv;
    1778           0 :     }
    1779           0 : 
    1780           0 :     MOZ_ASSERT(conn && !conn->Transaction(),
    1781             :                "DispatchTranaction() on non spdy active connection");
    1782             : 
    1783             :     rv = DispatchAbstractTransaction(ent, trans, caps, conn, priority);
    1784             : 
    1785             :     if (NS_SUCCEEDED(rv) && !trans->GetPendingTime().IsNull()) {
    1786             :         AccumulateTimeDelta(Telemetry::TRANSACTION_WAIT_TIME_HTTP,
    1787             :                             trans->GetPendingTime(), TimeStamp::Now());
    1788             :         trans->SetPendingTime(false);
    1789             :     }
    1790             :     return rv;
    1791             : }
    1792             : 
    1793             : //-----------------------------------------------------------------------------
    1794             : // ConnectionHandle
    1795             : //
    1796             : // thin wrapper around a real connection, used to keep track of references
    1797             : // to the connection to determine when the connection may be reused.  the
    1798             : // transaction owns a reference to this handle.  this extra
    1799             : // layer of indirection greatly simplifies consumer code, avoiding the
    1800           0 : // need for consumer code to know when to give the connection back to the
    1801             : // connection manager.
    1802           0 : //
    1803           0 : class ConnectionHandle : public nsAHttpConnection
    1804             : {
    1805             : public:
    1806             :     NS_DECL_THREADSAFE_ISUPPORTS
    1807             :     NS_DECL_NSAHTTPCONNECTION(mConn)
    1808             : 
    1809             :     explicit ConnectionHandle(nsHttpConnection *conn) : mConn(conn) { }
    1810           0 :     void Reset() { mConn = nullptr; }
    1811             : private:
    1812           0 :     virtual ~ConnectionHandle();
    1813             :     RefPtr<nsHttpConnection> mConn;
    1814             : };
    1815           0 : 
    1816             : nsAHttpConnection *
    1817           0 : nsHttpConnectionMgr::MakeConnectionHandle(nsHttpConnection *aWrapped)
    1818           0 : {
    1819           0 :     return new ConnectionHandle(aWrapped);
    1820           0 : }
    1821             : 
    1822             : ConnectionHandle::~ConnectionHandle()
    1823             : {
    1824           0 :     if (mConn) {
    1825             :         nsresult rv = gHttpHandler->ReclaimConnection(mConn);
    1826           0 :         if (NS_FAILED(rv)) {
    1827             :             LOG(("ConnectionHandle::~ConnectionHandle\n"
    1828             :                  "    failed to reclaim connection\n"));
    1829             :         }
    1830             :     }
    1831             : }
    1832             : 
    1833           0 : NS_IMPL_ISUPPORTS0(ConnectionHandle)
    1834             : 
    1835             : // Use this method for dispatching nsAHttpTransction's. It can only safely be
    1836             : // used upon first use of a connection when NPN has not negotiated SPDY vs
    1837             : // HTTP/1 yet as multiplexing onto an existing SPDY session requires a
    1838             : // concrete nsHttpTransaction
    1839           0 : nsresult
    1840             : nsHttpConnectionMgr::DispatchAbstractTransaction(nsConnectionEntry *ent,
    1841             :                                                  nsAHttpTransaction *aTrans,
    1842           0 :                                                  uint32_t caps,
    1843             :                                                  nsHttpConnection *conn,
    1844           0 :                                                  int32_t priority)
    1845             : {
    1846             :     MOZ_ASSERT(ent);
    1847             : 
    1848           0 :     nsresult rv;
    1849           0 :     MOZ_ASSERT(!conn->UsingSpdy(),
    1850             :                "Spdy Must Not Use DispatchAbstractTransaction");
    1851             :     LOG(("nsHttpConnectionMgr::DispatchAbstractTransaction "
    1852           0 :          "[ci=%s trans=%p caps=%x conn=%p]\n",
    1853             :          ent->mConnInfo->HashKey().get(), aTrans, caps, conn));
    1854           0 : 
    1855           0 :     RefPtr<nsAHttpTransaction> transaction(aTrans);
    1856           0 :     RefPtr<ConnectionHandle> handle = new ConnectionHandle(conn);
    1857           0 : 
    1858           0 :     // give the transaction the indirect reference to the connection.
    1859           0 :     transaction->SetConnection(handle);
    1860             : 
    1861             :     rv = conn->Activate(transaction, caps, priority);
    1862             :     if (NS_FAILED(rv)) {
    1863           0 :       LOG(("  conn->Activate failed [rv=%" PRIx32 "]\n", static_cast<uint32_t>(rv)));
    1864           0 :         ent->mActiveConns.RemoveElement(conn);
    1865             :         DecrementActiveConnCount(conn);
    1866             :         ConditionallyStopTimeoutTick();
    1867           0 : 
    1868             :         // sever back references to connection, and do so without triggering
    1869             :         // a call to ReclaimConnection ;-)
    1870             :         transaction->SetConnection(nullptr);
    1871           0 :         handle->Reset(); // destroy the connection
    1872             :     }
    1873             : 
    1874             :     return rv;
    1875           0 : }
    1876           0 : 
    1877           0 : void
    1878           0 : nsHttpConnectionMgr::ReportProxyTelemetry(nsConnectionEntry *ent)
    1879           0 : {
    1880           0 :     enum { PROXY_NONE = 1, PROXY_HTTP = 2, PROXY_SOCKS = 3, PROXY_HTTPS = 4 };
    1881             : 
    1882           0 :     if (!ent->mConnInfo->UsingProxy())
    1883           0 :         Telemetry::Accumulate(Telemetry::HTTP_PROXY_TYPE, PROXY_NONE);
    1884             :     else if (ent->mConnInfo->UsingHttpsProxy())
    1885             :         Telemetry::Accumulate(Telemetry::HTTP_PROXY_TYPE, PROXY_HTTPS);
    1886           0 :     else if (ent->mConnInfo->UsingHttpProxy())
    1887             :         Telemetry::Accumulate(Telemetry::HTTP_PROXY_TYPE, PROXY_HTTP);
    1888           0 :     else
    1889             :         Telemetry::Accumulate(Telemetry::HTTP_PROXY_TYPE, PROXY_SOCKS);
    1890             : }
    1891             : 
    1892             : nsresult
    1893             : nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
    1894           0 : {
    1895           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    1896             : 
    1897             :     // since "adds" and "cancels" are processed asynchronously and because
    1898             :     // various events might trigger an "add" directly on the socket thread,
    1899           0 :     // we must take care to avoid dispatching a transaction that has already
    1900             :     // been canceled (see bug 190001).
    1901           0 :     if (NS_FAILED(trans->Status())) {
    1902           0 :         LOG(("  transaction was canceled... dropping event!\n"));
    1903           0 :         return NS_OK;
    1904             :     }
    1905             : 
    1906           0 :     trans->SetPendingTime();
    1907             : 
    1908             :     Http2PushedStream *pushedStream = trans->GetPushedStream();
    1909             :     if (pushedStream) {
    1910           0 :         LOG(("  ProcessNewTransaction %p tied to h2 session push %p\n",
    1911           0 :              trans, pushedStream->Session()));
    1912           0 :         return pushedStream->Session()->
    1913             :             AddStream(trans, trans->Priority(), false, nullptr) ?
    1914             :             NS_OK : NS_ERROR_UNEXPECTED;
    1915           0 :     }
    1916           0 : 
    1917             :     nsresult rv = NS_OK;
    1918           0 :     nsHttpConnectionInfo *ci = trans->ConnectionInfo();
    1919             :     MOZ_ASSERT(ci);
    1920             : 
    1921             :     nsConnectionEntry *ent =
    1922             :         GetOrCreateConnectionEntry(ci, !!trans->TunnelProvider());
    1923             :     MOZ_ASSERT(ent);
    1924           0 : 
    1925           0 :     ReportProxyTelemetry(ent);
    1926           0 : 
    1927           0 :     // Check if the transaction already has a sticky reference to a connection.
    1928           0 :     // If so, then we can just use it directly by transferring its reference
    1929             :     // to the new connection variable instead of searching for a new one
    1930           0 : 
    1931           0 :     nsAHttpConnection *wrappedConnection = trans->Connection();
    1932           0 :     RefPtr<nsHttpConnection> conn;
    1933             :     RefPtr<PendingTransactionInfo> pendingTransInfo;
    1934             :     if (wrappedConnection)
    1935           0 :         conn = wrappedConnection->TakeHttpConnection();
    1936           0 : 
    1937             :     if (conn) {
    1938             :         MOZ_ASSERT(trans->Caps() & NS_HTTP_STICKY_CONNECTION);
    1939             :         LOG(("nsHttpConnectionMgr::ProcessNewTransaction trans=%p "
    1940             :              "sticky connection=%p\n", trans, conn.get()));
    1941           0 : 
    1942           0 :         if (static_cast<int32_t>(ent->mActiveConns.IndexOf(conn)) == -1) {
    1943             :             LOG(("nsHttpConnectionMgr::ProcessNewTransaction trans=%p "
    1944           0 :                  "sticky connection=%p needs to go on the active list\n", trans, conn.get()));
    1945             : 
    1946             :             // make sure it isn't on the idle list - we expect this to be an
    1947           0 :             // unknown fresh connection
    1948           0 :             MOZ_ASSERT(static_cast<int32_t>(ent->mIdleConns.IndexOf(conn)) == -1);
    1949             :             MOZ_ASSERT(!conn->IsExperienced());
    1950           0 : 
    1951           0 :             AddActiveConn(conn, ent); // make it active
    1952             :         }
    1953             : 
    1954           0 :         trans->SetConnection(nullptr);
    1955           0 :         rv = DispatchTransaction(ent, trans, conn);
    1956             :     } else {
    1957             :         pendingTransInfo = new PendingTransactionInfo(trans);
    1958             :         rv = TryDispatchTransaction(ent, !!trans->TunnelProvider(), pendingTransInfo);
    1959           0 :     }
    1960           0 : 
    1961           0 :     if (NS_SUCCEEDED(rv)) {
    1962             :         LOG(("  ProcessNewTransaction Dispatch Immediately trans=%p\n", trans));
    1963           0 :         return rv;
    1964           0 :     }
    1965             : 
    1966             :     if (rv == NS_ERROR_NOT_AVAILABLE) {
    1967             :         if (!pendingTransInfo) {
    1968           0 :             pendingTransInfo = new PendingTransactionInfo(trans);
    1969             :         }
    1970           0 :         if (trans->Caps() & NS_HTTP_URGENT_START) {
    1971             :             LOG(("  adding transaction to pending queue "
    1972             :                  "[trans=%p urgent-start-count=%zu]\n",
    1973             :                  trans, ent->mUrgentStartQ.Length() + 1));
    1974           0 :             // put this transaction on the urgent-start queue...
    1975             :             InsertTransactionSorted(ent->mUrgentStartQ, pendingTransInfo);
    1976             :         } else {
    1977             :             LOG(("  adding transaction to pending queue "
    1978             :                  "[trans=%p pending-count=%zu]\n",
    1979           0 :                  trans, ent->PendingQLength() + 1));
    1980             :             // put this transaction on the pending queue...
    1981             :             ent->InsertTransaction(pendingTransInfo);
    1982             :         }
    1983             :         return NS_OK;
    1984             :     }
    1985             : 
    1986           0 :     LOG(("  ProcessNewTransaction Hard Error trans=%p rv=%" PRIx32 "\n",
    1987             :          trans, static_cast<uint32_t>(rv)));
    1988             :     return rv;
    1989           0 : }
    1990           0 : 
    1991           0 : 
    1992           0 : void
    1993             : nsHttpConnectionMgr::AddActiveConn(nsHttpConnection *conn,
    1994             :                                    nsConnectionEntry *ent)
    1995           0 : {
    1996             :     ent->mActiveConns.AppendElement(conn);
    1997           0 :     mNumActiveConns++;
    1998           0 :     ActivateTimeoutTick();
    1999           0 : }
    2000           0 : 
    2001             : void
    2002             : nsHttpConnectionMgr::DecrementActiveConnCount(nsHttpConnection *conn)
    2003           0 : {
    2004             :     mNumActiveConns--;
    2005           0 :     if (conn->EverUsedSpdy())
    2006           0 :         mNumSpdyActiveConns--;
    2007           0 : }
    2008             : 
    2009             : void
    2010           0 : nsHttpConnectionMgr::StartedConnect()
    2011             : {
    2012           0 :     mNumActiveConns++;
    2013           0 :     ActivateTimeoutTick(); // likely disabled by RecvdConnect()
    2014           0 : }
    2015             : 
    2016             : void
    2017           0 : nsHttpConnectionMgr::RecvdConnect()
    2018             : {
    2019             :     mNumActiveConns--;
    2020           0 :     ConditionallyStopTimeoutTick();
    2021             : }
    2022           0 : 
    2023           0 : void
    2024             : nsHttpConnectionMgr::ReleaseClaimedSockets(nsConnectionEntry *ent,
    2025             :                                            PendingTransactionInfo * pendingTransInfo)
    2026             : {
    2027           0 :     if (pendingTransInfo->mHalfOpen) {
    2028           0 :         RefPtr<nsHalfOpenSocket> halfOpen =
    2029             :             do_QueryReferent(pendingTransInfo->mHalfOpen);
    2030           0 :         LOG(("nsHttpConnectionMgr::ReleaseClaimedSockets "
    2031           0 :              "[trans=%p halfOpen=%p]",
    2032             :              pendingTransInfo->mTransaction.get(),
    2033           0 :              halfOpen.get()));
    2034           0 :         if (halfOpen) {
    2035           0 :             halfOpen->Unclaim();
    2036           0 :         }
    2037           0 :         pendingTransInfo->mHalfOpen = nullptr;
    2038           0 :     } else if (pendingTransInfo->mActiveConn) {
    2039             :         RefPtr<nsHttpConnection> activeConn =
    2040             :             do_QueryReferent(pendingTransInfo->mActiveConn);
    2041             :         if (activeConn && activeConn->Transaction() &&
    2042           0 :             activeConn->Transaction()->IsNullTransaction()) {
    2043             :             NullHttpTransaction *nullTrans = activeConn->Transaction()->QueryNullTransaction();
    2044             :             nullTrans->Unclaim();
    2045           0 :             LOG(("nsHttpConnectionMgr::ReleaseClaimedSockets - mark %p unclaimed.",
    2046             :                  activeConn.get()));
    2047             :         }
    2048             :     }
    2049             : }
    2050             : 
    2051             : nsresult
    2052             : nsHttpConnectionMgr::CreateTransport(nsConnectionEntry *ent,
    2053             :                                      nsAHttpTransaction *trans,
    2054           0 :                                      uint32_t caps,
    2055           0 :                                      bool speculative,
    2056             :                                      bool isFromPredictor,
    2057             :                                      bool urgentStart,
    2058             :                                      bool allow1918,
    2059             :                                      PendingTransactionInfo *pendingTransInfo)
    2060             : {
    2061           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2062             :     MOZ_ASSERT((speculative && !pendingTransInfo) ||
    2063           0 :                (!speculative && pendingTransInfo));
    2064           0 : 
    2065             :     RefPtr<nsHalfOpenSocket> sock = new nsHalfOpenSocket(ent, trans, caps,
    2066             :                                                          speculative,
    2067             :                                                          isFromPredictor,
    2068             :                                                          urgentStart);
    2069           0 : 
    2070           0 :     if (speculative) {
    2071             :         sock->SetAllow1918(allow1918);
    2072           0 :     }
    2073             :     // The socket stream holds the reference to the half open
    2074           0 :     // socket - so if the stream fails to init the half open
    2075           0 :     // will go away.
    2076           0 :     nsresult rv = sock->SetupPrimaryStreams();
    2077             :     NS_ENSURE_SUCCESS(rv, rv);
    2078             : 
    2079           0 :     if (pendingTransInfo) {
    2080           0 :         pendingTransInfo->mHalfOpen =
    2081           0 :             do_GetWeakReference(static_cast<nsISupportsWeakReference*>(sock));
    2082             :         DebugOnly<bool> claimed = sock->Claim();
    2083             :         MOZ_ASSERT(claimed);
    2084             :     }
    2085           0 : 
    2086             :     ent->mHalfOpens.AppendElement(sock);
    2087             :     mNumHalfOpenConns++;
    2088             :     return NS_OK;
    2089           0 : }
    2090           0 : 
    2091             : void
    2092             : nsHttpConnectionMgr::DispatchSpdyPendingQ(nsTArray<RefPtr<PendingTransactionInfo>> &pendingQ,
    2093           0 :                                           nsConnectionEntry *ent,
    2094             :                                           nsHttpConnection *conn)
    2095             : {
    2096           0 :     if (pendingQ.Length() == 0) {
    2097           0 :         return;
    2098             :     }
    2099           0 : 
    2100             :     nsTArray<RefPtr<PendingTransactionInfo>> leftovers;
    2101           0 :     uint32_t index;
    2102           0 :     // Dispatch all the transactions we can
    2103           0 :     for (index = 0;
    2104           0 :          index < pendingQ.Length() && conn->CanDirectlyActivate();
    2105             :          ++index) {
    2106             :         PendingTransactionInfo *pendingTransInfo = pendingQ[index];
    2107           0 : 
    2108           0 :         if (!(pendingTransInfo->mTransaction->Caps() & NS_HTTP_ALLOW_KEEPALIVE) ||
    2109           0 :             pendingTransInfo->mTransaction->Caps() & NS_HTTP_DISALLOW_SPDY) {
    2110             :             leftovers.AppendElement(pendingTransInfo);
    2111             :             continue;
    2112           0 :         }
    2113             : 
    2114             :         nsresult rv = DispatchTransaction(ent, pendingTransInfo->mTransaction,
    2115             :                                           conn);
    2116             :         if (NS_FAILED(rv)) {
    2117           0 :             // this cannot happen, but if due to some bug it does then
    2118             :             // close the transaction
    2119             :             MOZ_ASSERT(false, "Dispatch SPDY Transaction");
    2120             :             LOG(("ProcessSpdyPendingQ Dispatch Transaction failed trans=%p\n",
    2121             :                  pendingTransInfo->mTransaction.get()));
    2122           0 :             pendingTransInfo->mTransaction->Close(rv);
    2123           0 :         }
    2124           0 :         ReleaseClaimedSockets(ent, pendingTransInfo);
    2125             :     }
    2126             : 
    2127             :     // Slurp up the rest of the pending queue into our leftovers bucket (we
    2128             :     // might have some left if conn->CanDirectlyActivate returned false)
    2129           0 :     for (; index < pendingQ.Length(); ++index) {
    2130           0 :         PendingTransactionInfo *pendingTransInfo = pendingQ[index];
    2131             :         leftovers.AppendElement(pendingTransInfo);
    2132             :     }
    2133             : 
    2134             :     // Put the leftovers back in the pending queue and get rid of the
    2135             :     // transactions we dispatched
    2136             :     leftovers.SwapElements(pendingQ);
    2137             :     leftovers.Clear();
    2138             : }
    2139           0 : 
    2140             : // This function tries to dispatch the pending spdy transactions on
    2141           0 : // the connection entry sent in as an argument. It will do so on the
    2142           0 : // active spdy connection either in that same entry or from the
    2143           0 : // coalescing hash table
    2144             : 
    2145             : void
    2146           0 : nsHttpConnectionMgr::ProcessSpdyPendingQ(nsConnectionEntry *ent)
    2147           0 : {
    2148             :     nsHttpConnection *conn = GetSpdyActiveConn(ent);
    2149             :     if (!conn || !conn->CanDirectlyActivate()) {
    2150             :         return;
    2151           0 :     }
    2152             : 
    2153           0 :     DispatchSpdyPendingQ(ent->mUrgentStartQ, ent, conn);
    2154           0 :     if (!conn->CanDirectlyActivate()) {
    2155             :         return;
    2156             :     }
    2157           0 : 
    2158           0 :     nsTArray<RefPtr<PendingTransactionInfo>> pendingQ;
    2159             :     // XXX Get all transactions for SPDY currently.
    2160             :     ent->AppendPendingQForNonFocusedWindows(0, pendingQ);
    2161             :     DispatchSpdyPendingQ(pendingQ, ent, conn);
    2162             : 
    2163           0 :     // Put the leftovers back in the pending queue.
    2164             :     for (const auto& transactionInfo : pendingQ) {
    2165           0 :         ent->InsertTransaction(transactionInfo);
    2166           0 :     }
    2167           0 : }
    2168           0 : 
    2169             : void
    2170           0 : nsHttpConnectionMgr::OnMsgProcessAllSpdyPendingQ(int32_t, ARefBase *)
    2171             : {
    2172             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2173             :     LOG(("nsHttpConnectionMgr::OnMsgProcessAllSpdyPendingQ\n"));
    2174             :     for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
    2175           0 :         ProcessSpdyPendingQ(iter.Data().get());
    2176             :     }
    2177           0 : }
    2178           0 : 
    2179             : // Given a connection entry, return an active h2 connection
    2180           0 : // that can be directly activated or null
    2181           0 : nsHttpConnection *
    2182           0 : nsHttpConnectionMgr::GetSpdyActiveConn(nsConnectionEntry *ent)
    2183           0 : {
    2184             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2185             :     MOZ_ASSERT(ent);
    2186             : 
    2187             :     nsHttpConnection *experienced = nullptr;
    2188           0 :     nsHttpConnection *noExperience = nullptr;
    2189           0 :     uint32_t activeLen = ent->mActiveConns.Length();
    2190           0 :     nsHttpConnectionInfo *ci = ent->mConnInfo;
    2191           0 :     uint32_t index;
    2192             : 
    2193             :     // activeLen should generally be 1.. this is a setup race being resolved
    2194             :     // take a conn who can activate and is experienced
    2195             :     for (index = 0; index < activeLen; ++index) {
    2196             :         nsHttpConnection *tmp = ent->mActiveConns[index];
    2197             :         if (tmp->CanDirectlyActivate()) {
    2198             :             if (tmp->IsExperienced()) {
    2199             :                 experienced = tmp;
    2200           0 :                 break;
    2201           0 :             }
    2202           0 :             noExperience = tmp; // keep looking for a better option
    2203             :         }
    2204           0 :     }
    2205           0 : 
    2206             :     // if that worked, cleanup anything else and exit
    2207             :     if (experienced) {
    2208           0 :         for (index = 0; index < activeLen; ++index) {
    2209           0 :             nsHttpConnection *tmp = ent->mActiveConns[index];
    2210             :             // in the case where there is a functional h2 session, drop the others
    2211             :             if (tmp != experienced) {
    2212             :                 tmp->DontReuse();
    2213           0 :             }
    2214           0 :         }
    2215             :         for (int32_t index = ent->mHalfOpenFastOpenBackups.Length() - 1; index >= 0; --index) {
    2216             :              LOG(("GetSpdyActiveConn() shutting down connection in fast "
    2217           0 :                  "open state (%p) because we have an experienced spdy "
    2218             :                  "connection (%p).\n",
    2219             :                  ent->mHalfOpenFastOpenBackups[index].get(), experienced));
    2220             :              RefPtr<nsHalfOpenSocket> half = ent->mHalfOpenFastOpenBackups[index];
    2221             :              half->CancelFastOpenConnection();
    2222             :         }
    2223           0 : 
    2224           0 :         LOG(("GetSpdyActiveConn() request for ent %p %s "
    2225             :              "found an active experienced connection %p in native connection entry\n",
    2226             :              ent, ci->HashKey().get(), experienced));
    2227             :         return experienced;
    2228             :     }
    2229             : 
    2230             :     if (noExperience) {
    2231             :         LOG(("GetSpdyActiveConn() request for ent %p %s "
    2232           0 :              "found an active but inexperienced connection %p in native connection entry\n",
    2233           0 :              ent, ci->HashKey().get(), noExperience));
    2234           0 :         return noExperience;
    2235             :     }
    2236             : 
    2237             :     // there was no active spdy connection in the connection entry, but
    2238             :     // there might be one in the hash table for coalescing
    2239             :     nsHttpConnection *existingConn = FindCoalescableConnection(ent, false);
    2240           0 :     if (existingConn) {
    2241             :         LOG(("GetSpdyActiveConn() request for ent %p %s "
    2242             :              "found an active connection %p in the coalescing hashtable\n",
    2243             :              ent, ci->HashKey().get(), existingConn));
    2244             :         return existingConn;
    2245             :     }
    2246             : 
    2247             :     LOG(("GetSpdyActiveConn() request for ent %p %s "
    2248           0 :          "did not find an active connection\n", ent, ci->HashKey().get()));
    2249             :     return nullptr;
    2250           0 : }
    2251           0 : 
    2252           0 : //-----------------------------------------------------------------------------
    2253             : 
    2254             : void
    2255           0 : nsHttpConnectionMgr::AbortAndCloseAllConnections(int32_t, ARefBase *)
    2256           0 : {
    2257           0 :     if (!OnSocketThread()) {
    2258           0 :         Unused << PostEvent(&nsHttpConnectionMgr::AbortAndCloseAllConnections);
    2259             :         return;
    2260             :     }
    2261           0 : 
    2262           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2263           0 :     LOG(("nsHttpConnectionMgr::AbortAndCloseAllConnections\n"));
    2264           0 :     for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
    2265             :         RefPtr<nsConnectionEntry> ent = iter.Data();
    2266             : 
    2267             :         // Close all active connections.
    2268           0 :         while (ent->mActiveConns.Length()) {
    2269             :             RefPtr<nsHttpConnection> conn(ent->mActiveConns[0]);
    2270             :             ent->mActiveConns.RemoveElementAt(0);
    2271             :             DecrementActiveConnCount(conn);
    2272           0 :             // Since nsHttpConnection::Close doesn't break the bond with
    2273           0 :             // the connection's transaction, we must explicitely tell it
    2274             :             // to close its transaction and not just self.
    2275           0 :             conn->CloseTransaction(conn->Transaction(), NS_ERROR_ABORT, true);
    2276           0 :         }
    2277             : 
    2278           0 :         // Close all idle connections.
    2279             :         while (ent->mIdleConns.Length()) {
    2280             :             RefPtr<nsHttpConnection> conn(ent->mIdleConns[0]);
    2281             : 
    2282             :             ent->mIdleConns.RemoveElementAt(0);
    2283           0 :             mNumIdleConns--;
    2284             : 
    2285             :             conn->Close(NS_ERROR_ABORT);
    2286           0 :         }
    2287           0 : 
    2288           0 :         // If all idle connections are removed we can stop pruning dead
    2289           0 :         // connections.
    2290             :         ConditionallyStopPruneDeadConnectionsTimer();
    2291             : 
    2292             :         // Close all urgentStart transactions.
    2293           0 :         while (ent->mUrgentStartQ.Length()) {
    2294           0 :             PendingTransactionInfo *pendingTransInfo = ent->mUrgentStartQ[0];
    2295           0 :             pendingTransInfo->mTransaction->Close(NS_ERROR_ABORT);
    2296           0 :             ent->mUrgentStartQ.RemoveElementAt(0);
    2297           0 :         }
    2298           0 : 
    2299           0 :         // Close all pending transactions.
    2300             :         for (auto it = ent->mPendingTransactionTable.Iter();
    2301             :              !it.Done();
    2302           0 :              it.Next()) {
    2303             :             while (it.UserData()->Length()) {
    2304             :                 PendingTransactionInfo *pendingTransInfo = (*it.UserData())[0];
    2305           0 :                 pendingTransInfo->mTransaction->Close(NS_ERROR_ABORT);
    2306           0 :                 it.UserData()->RemoveElementAt(0);
    2307             :             }
    2308             :         }
    2309           0 :         ent->mPendingTransactionTable.Clear();
    2310             : 
    2311           0 :         // Close all half open tcp connections.
    2312             :         for (int32_t i = int32_t(ent->mHalfOpens.Length()) - 1; i >= 0; i--) {
    2313             :             ent->mHalfOpens[i]->Abandon();
    2314           0 :         }
    2315           0 : 
    2316             :         MOZ_ASSERT(ent->mHalfOpenFastOpenBackups.Length() == 0 &&
    2317             :                    !ent->mDoNotDestroy);
    2318             :         iter.Remove();
    2319           0 :     }
    2320             : 
    2321           0 :     mActiveTransactions[false].Clear();
    2322           0 :     mActiveTransactions[true].Clear();
    2323             : }
    2324           0 : 
    2325           0 : void
    2326             : nsHttpConnectionMgr::OnMsgShutdown(int32_t, ARefBase *param)
    2327             : {
    2328             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2329           0 :     LOG(("nsHttpConnectionMgr::OnMsgShutdown\n"));
    2330             : 
    2331           0 :     gHttpHandler->StopRequestTokenBucket();
    2332           0 :     AbortAndCloseAllConnections(0, nullptr);
    2333           0 : 
    2334           0 :     // If all idle connections are removed we can stop pruning dead
    2335             :     // connections.
    2336           0 :     ConditionallyStopPruneDeadConnectionsTimer();
    2337           0 : 
    2338           0 :     if (mTimeoutTick) {
    2339             :         mTimeoutTick->Cancel();
    2340           0 :         mTimeoutTick = nullptr;
    2341           0 :         mTimeoutTickArmed = false;
    2342           0 :     }
    2343             :     if (mTimer) {
    2344           0 :       mTimer->Cancel();
    2345             :       mTimer = nullptr;
    2346           0 :     }
    2347             :     if (mTrafficTimer) {
    2348             :       mTrafficTimer->Cancel();
    2349             :       mTrafficTimer = nullptr;
    2350             :     }
    2351           0 :     DestroyThrottleTicker();
    2352           0 : 
    2353           0 :     mCoalescingHash.Clear();
    2354             : 
    2355             :     // signal shutdown complete
    2356           0 :     nsCOMPtr<nsIRunnable> runnable =
    2357             :         new ConnEvent(this, &nsHttpConnectionMgr::OnMsgShutdownConfirm,
    2358           0 :                       0, param);
    2359           0 :     NS_DispatchToMainThread(runnable);
    2360             : }
    2361           0 : 
    2362           0 : void
    2363           0 : nsHttpConnectionMgr::OnMsgShutdownConfirm(int32_t priority, ARefBase *param)
    2364             : {
    2365             :     MOZ_ASSERT(NS_IsMainThread());
    2366           0 :     LOG(("nsHttpConnectionMgr::OnMsgShutdownConfirm\n"));
    2367             : 
    2368           0 :     BoolWrapper *shutdown = static_cast<BoolWrapper *>(param);
    2369             :     shutdown->mBool = true;
    2370           0 : }
    2371           0 : 
    2372           0 : void
    2373           0 : nsHttpConnectionMgr::OnMsgNewTransaction(int32_t priority, ARefBase *param)
    2374           0 : {
    2375           0 :     LOG(("nsHttpConnectionMgr::OnMsgNewTransaction [trans=%p]\n", param));
    2376             : 
    2377           0 :     nsHttpTransaction *trans = static_cast<nsHttpTransaction *>(param);
    2378             :     trans->SetPriority(priority);
    2379           0 :     nsresult rv = ProcessNewTransaction(trans);
    2380           0 :     if (NS_FAILED(rv))
    2381           0 :         trans->Close(rv); // for whatever its worth
    2382             : }
    2383             : 
    2384             : static uint64_t TabIdForQueuing(nsAHttpTransaction *transaction)
    2385           0 : {
    2386             :   return gHttpHandler->ActiveTabPriority()
    2387             :       ? transaction->TopLevelOuterContentWindowId()
    2388           0 :       : 0;
    2389           0 : }
    2390           0 : 
    2391           0 : nsTArray<RefPtr<nsHttpConnectionMgr::PendingTransactionInfo>>*
    2392             : nsHttpConnectionMgr::GetTransactionPendingQHelper(nsConnectionEntry *ent,
    2393             :                                                   nsAHttpTransaction *trans)
    2394           0 : {
    2395             :     nsTArray<RefPtr<PendingTransactionInfo>> *pendingQ = nullptr;
    2396           0 :     int32_t caps = trans->Caps();
    2397             :     if (caps & NS_HTTP_URGENT_START) {
    2398             :         pendingQ = &(ent->mUrgentStartQ);
    2399             :     } else {
    2400           0 :         pendingQ =
    2401             :             ent->mPendingTransactionTable.Get(TabIdForQueuing(trans));
    2402           0 :     }
    2403           0 :     return pendingQ;
    2404             : }
    2405           0 : 
    2406           0 : void
    2407             : nsHttpConnectionMgr::OnMsgReschedTransaction(int32_t priority, ARefBase *param)
    2408           0 : {
    2409           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2410             :     LOG(("nsHttpConnectionMgr::OnMsgReschedTransaction [trans=%p]\n", param));
    2411           0 : 
    2412             :     RefPtr<nsHttpTransaction> trans = static_cast<nsHttpTransaction *>(param);
    2413           0 :     trans->SetPriority(priority);
    2414             : 
    2415           0 :     if (!trans->ConnectionInfo()) {
    2416             :         return;
    2417             :     }
    2418           0 :     nsConnectionEntry *ent = mCT.GetWeak(trans->ConnectionInfo()->HashKey());
    2419           0 : 
    2420           0 :     if (ent) {
    2421           0 :         nsTArray<RefPtr<PendingTransactionInfo>> *pendingQ =
    2422           0 :             GetTransactionPendingQHelper(ent, trans);
    2423           0 : 
    2424             :         int32_t index = pendingQ
    2425             :             ? pendingQ->IndexOf(trans, 0, PendingComparator())
    2426             :             : -1;
    2427             :         if (index >= 0) {
    2428           0 :             RefPtr<PendingTransactionInfo> pendingTransInfo = (*pendingQ)[index];
    2429             :             pendingQ->RemoveElementAt(index);
    2430           0 :             InsertTransactionSorted(*pendingQ, pendingTransInfo);
    2431           0 :         }
    2432             :     }
    2433           0 : }
    2434           0 : 
    2435             : void nsHttpConnectionMgr::OnMsgUpdateClassOfServiceOnTransaction(int32_t arg, ARefBase *param)
    2436           0 : {
    2437           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2438             :     LOG(("nsHttpConnectionMgr::OnMsgUpdateClassOfServiceOnTransaction [trans=%p]\n", param));
    2439           0 : 
    2440           0 :     uint32_t cos = static_cast<uint32_t>(arg);
    2441             :     nsHttpTransaction *trans = static_cast<nsHttpTransaction *>(param);
    2442           0 : 
    2443             :     uint32_t previous = trans->ClassOfService();
    2444             :     trans->SetClassOfService(cos);
    2445           0 : 
    2446             :     if ((previous ^ cos) & (NS_HTTP_LOAD_AS_BLOCKING | NS_HTTP_LOAD_UNBLOCKED)) {
    2447           0 :         Unused << RescheduleTransaction(trans, trans->Priority());
    2448           0 :     }
    2449             : }
    2450           0 : 
    2451             : void
    2452             : nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, ARefBase *param)
    2453           0 : {
    2454             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2455             :     LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]\n", param));
    2456             : 
    2457             :     nsresult closeCode = static_cast<nsresult>(reason);
    2458             : 
    2459             :     // caller holds a ref to param/trans on stack
    2460           0 :     nsHttpTransaction *trans = static_cast<nsHttpTransaction *>(param);
    2461           0 : 
    2462           0 :     //
    2463             :     // if the transaction owns a connection and the transaction is not done,
    2464           0 :     // then ask the connection to close the transaction.  otherwise, close the
    2465           0 :     // transaction directly (removing it from the pending queue first).
    2466           0 :     //
    2467             :     RefPtr<nsAHttpConnection> conn(trans->Connection());
    2468           0 :     if (conn && !trans->IsDone()) {
    2469             :         conn->CloseTransaction(trans, closeCode);
    2470             :     } else {
    2471             :         nsConnectionEntry *ent = nullptr;
    2472             :         if (trans->ConnectionInfo()) {
    2473           0 :             ent = mCT.GetWeak(trans->ConnectionInfo()->HashKey());
    2474             :         }
    2475           0 :         if (ent) {
    2476           0 :             int32_t transIndex;
    2477           0 :             // We will abandon all half-open sockets belonging to the given
    2478           0 :             // transaction.
    2479           0 :             nsTArray<RefPtr<PendingTransactionInfo>> *infoArray =
    2480           0 :                 GetTransactionPendingQHelper(ent, trans);
    2481             : 
    2482           0 :             RefPtr<PendingTransactionInfo> pendingTransInfo;
    2483             :             transIndex = infoArray
    2484             :                 ? infoArray->IndexOf(trans, 0, PendingComparator())
    2485           0 :                 : -1;
    2486             :             if (transIndex >=0) {
    2487             :                 LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]"
    2488             :                      " found in urgentStart queue\n", trans));
    2489           0 :                 pendingTransInfo = (*infoArray)[transIndex];
    2490             :                 // We do not need to ReleaseClaimedSockets while we are
    2491           0 :                 // going to close them all any way!
    2492           0 :                 infoArray->RemoveElementAt(transIndex);
    2493           0 :             }
    2494             : 
    2495           0 :             // Abandon all half-open sockets belonging to the given transaction.
    2496             :             if (pendingTransInfo) {
    2497             :                 RefPtr<nsHalfOpenSocket> half =
    2498             :                     do_QueryReferent(pendingTransInfo->mHalfOpen);
    2499           0 :                 if (half) {
    2500             :                     half->Abandon();
    2501             :                 }
    2502             :                 pendingTransInfo->mHalfOpen = nullptr;
    2503             :             }
    2504             :         }
    2505             : 
    2506             :         trans->Close(closeCode);
    2507           0 : 
    2508           0 :         // Cancel is a pretty strong signal that things might be hanging
    2509             :         // so we want to cancel any null transactions related to this connection
    2510           0 :         // entry. They are just optimizations, but they aren't hooked up to
    2511           0 :         // anything that might get canceled from the rest of gecko, so best
    2512           0 :         // to assume that's what was meant by the cancel we did receive if
    2513           0 :         // it only applied to something in the queue.
    2514             :         for (uint32_t index = 0;
    2515             :              ent && (index < ent->mActiveConns.Length());
    2516           0 :              ++index) {
    2517             :             nsHttpConnection *activeConn = ent->mActiveConns[index];
    2518             :             nsAHttpTransaction *liveTransaction = activeConn->Transaction();
    2519             :             if (liveTransaction && liveTransaction->IsNullTransaction()) {
    2520           0 :                 LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p] "
    2521             :                      "also canceling Null Transaction %p on conn %p\n",
    2522             :                      trans, liveTransaction, activeConn));
    2523           0 :                 activeConn->CloseTransaction(liveTransaction, closeCode);
    2524             :             }
    2525           0 :         }
    2526           0 :     }
    2527             : }
    2528           0 : 
    2529           0 : void
    2530             : nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, ARefBase *param)
    2531           0 : {
    2532           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2533             :     nsHttpConnectionInfo *ci = static_cast<nsHttpConnectionInfo *>(param);
    2534           0 : 
    2535             :     if (!ci) {
    2536             :         LOG(("nsHttpConnectionMgr::OnMsgProcessPendingQ [ci=nullptr]\n"));
    2537           0 :         // Try and dispatch everything
    2538             :         for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
    2539             :             Unused << ProcessPendingQForEntry(iter.Data().get(), true);
    2540             :         }
    2541           0 :         return;
    2542           0 :     }
    2543             : 
    2544             :     LOG(("nsHttpConnectionMgr::OnMsgProcessPendingQ [ci=%s]\n",
    2545           0 :          ci->HashKey().get()));
    2546           0 : 
    2547             :     // start by processing the queue identified by the given connection info.
    2548             :     nsConnectionEntry *ent = mCT.GetWeak(ci->HashKey());
    2549             :     if (!(ent && ProcessPendingQForEntry(ent, false))) {
    2550             :         // if we reach here, it means that we couldn't dispatch a transaction
    2551             :         // for the specified connection info.  walk the connection table...
    2552             :         for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
    2553             :             if (ProcessPendingQForEntry(iter.Data().get(), false)) {
    2554           0 :                 break;
    2555             :             }
    2556           0 :         }
    2557             :     }
    2558           0 : }
    2559           0 : 
    2560             : nsresult
    2561             : nsHttpConnectionMgr::CancelTransactions(nsHttpConnectionInfo *ci, nsresult code)
    2562             : {
    2563           0 :     LOG(("nsHttpConnectionMgr::CancelTransactions %s\n",ci->HashKey().get()));
    2564             : 
    2565             :     int32_t intReason = static_cast<int32_t>(code);
    2566             :     return PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransactions, intReason, ci);
    2567             : }
    2568             : 
    2569           0 : void
    2570           0 : nsHttpConnectionMgr::CancelTransactionsHelper(
    2571             :     nsTArray<RefPtr<nsHttpConnectionMgr::PendingTransactionInfo>> &pendingQ,
    2572           0 :     const nsHttpConnectionInfo *ci,
    2573             :     const nsHttpConnectionMgr::nsConnectionEntry *ent,
    2574           0 :     nsresult reason)
    2575           0 : {
    2576             :     for (const auto& pendingTransInfo : pendingQ) {
    2577             :         LOG(("nsHttpConnectionMgr::OnMsgCancelTransactions %s %p %p\n",
    2578           0 :              ci->HashKey().get(), ent, pendingTransInfo->mTransaction.get()));
    2579             :         pendingTransInfo->mTransaction->Close(reason);
    2580           0 :     }
    2581           0 :     pendingQ.Clear();
    2582           0 : }
    2583           0 : 
    2584             : void
    2585           0 : nsHttpConnectionMgr::OnMsgCancelTransactions(int32_t code, ARefBase *param)
    2586             : {
    2587             :     nsresult reason = static_cast<nsresult>(code);
    2588             :     nsHttpConnectionInfo *ci = static_cast<nsHttpConnectionInfo *>(param);
    2589           0 :     nsConnectionEntry *ent = mCT.GetWeak(ci->HashKey());
    2590             :     LOG(("nsHttpConnectionMgr::OnMsgCancelTransactions %s %p\n",
    2591           0 :          ci->HashKey().get(), ent));
    2592           0 :     if (!ent) {
    2593           0 :         return;
    2594           0 :     }
    2595             : 
    2596           0 :     CancelTransactionsHelper(ent->mUrgentStartQ, ci, ent, reason);
    2597             : 
    2598             :     for (auto it = ent->mPendingTransactionTable.Iter();
    2599             :          !it.Done();
    2600           0 :          it.Next()) {
    2601             :         CancelTransactionsHelper(*it.UserData(), ci, ent, reason);
    2602           0 :     }
    2603           0 :     ent->mPendingTransactionTable.Clear();
    2604             : }
    2605             : 
    2606           0 : void
    2607             : nsHttpConnectionMgr::OnMsgPruneDeadConnections(int32_t, ARefBase *)
    2608             : {
    2609             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2610           0 :     LOG(("nsHttpConnectionMgr::OnMsgPruneDeadConnections\n"));
    2611           0 : 
    2612           0 :     // Reset mTimeOfNextWakeUp so that we can find a new shortest value.
    2613             :     mTimeOfNextWakeUp = UINT64_MAX;
    2614           0 : 
    2615             :     // check canreuse() for all idle connections plus any active connections on
    2616             :     // connection entries that are using spdy.
    2617             :     if (mNumIdleConns || (mNumActiveConns && gHttpHandler->IsSpdyEnabled())) {
    2618           0 :         for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
    2619           0 :             RefPtr<nsConnectionEntry> ent = iter.Data();
    2620           0 : 
    2621           0 :             LOG(("  pruning [ci=%s]\n", ent->mConnInfo->HashKey().get()));
    2622           0 : 
    2623           0 :             // Find out how long it will take for next idle connection to not
    2624           0 :             // be reusable anymore.
    2625           0 :             uint32_t timeToNextExpire = UINT32_MAX;
    2626           0 :             int32_t count = ent->mIdleConns.Length();
    2627             :             if (count > 0) {
    2628           0 :                 for (int32_t i = count - 1; i >= 0; --i) {
    2629           0 :                     RefPtr<nsHttpConnection> conn(ent->mIdleConns[i]);
    2630             :                     if (!conn->CanReuse()) {
    2631             :                         ent->mIdleConns.RemoveElementAt(i);
    2632             :                         conn->Close(NS_ERROR_ABORT);
    2633             :                         mNumIdleConns--;
    2634           0 :                     } else {
    2635           0 :                         timeToNextExpire =
    2636           0 :                             std::min(timeToNextExpire, conn->TimeToLive());
    2637           0 :                     }
    2638           0 :                 }
    2639             :             }
    2640             : 
    2641           0 :             if (ent->mUsingSpdy) {
    2642             :                 for (uint32_t i = 0; i < ent->mActiveConns.Length(); ++i) {
    2643           0 :                     nsHttpConnection* conn = ent->mActiveConns[i];
    2644           0 :                     if (conn->UsingSpdy()) {
    2645             :                         if (!conn->CanReuse()) {
    2646             :                             // Marking it don't-reuse will create an active
    2647             :                             // tear down if the spdy session is idle.
    2648             :                             conn->DontReuse();
    2649             :                         } else {
    2650             :                             timeToNextExpire =
    2651             :                                 std::min(timeToNextExpire, conn->TimeToLive());
    2652           0 :                         }
    2653           0 :                     }
    2654           0 :                 }
    2655             :             }
    2656             : 
    2657             :             // If time to next expire found is shorter than time to next
    2658             :             // wake-up, we need to change the time for next wake-up.
    2659           0 :             if (timeToNextExpire != UINT32_MAX) {
    2660           0 :                 uint32_t now = NowInSeconds();
    2661             :                 uint64_t timeOfNextExpire = now + timeToNextExpire;
    2662             :                 // If pruning of dead connections is not already scheduled to
    2663           0 :                 // happen or time found for next connection to expire is is
    2664             :                 // before mTimeOfNextWakeUp, we need to schedule the pruning to
    2665             :                 // happen after timeToNextExpire.
    2666           0 :                 if (!mTimer || timeOfNextExpire < mTimeOfNextWakeUp) {
    2667             :                     PruneDeadConnectionsAfter(timeToNextExpire);
    2668             :                 }
    2669             :             } else {
    2670           0 :                 ConditionallyStopPruneDeadConnectionsTimer();
    2671           0 :             }
    2672           0 : 
    2673           0 :             ent->RemoveEmptyPendingQ();
    2674           0 : 
    2675           0 :             // If this entry is empty, we have too many entries busy then
    2676           0 :             // we can clean it up and restart
    2677           0 :             if (mCT.Count()                 >  125 &&
    2678           0 :                 ent->mIdleConns.Length()    == 0 &&
    2679           0 :                 ent->mActiveConns.Length()  == 0 &&
    2680           0 :                 ent->mHalfOpens.Length()    == 0 &&
    2681           0 :                 ent->PendingQLength()       == 0 &&
    2682             :                 ent->mUrgentStartQ.Length() == 0 &&
    2683             :                 ent->mHalfOpenFastOpenBackups.Length() == 0 &&
    2684             :                 !ent->mDoNotDestroy &&
    2685           0 :                 (!ent->mUsingSpdy || mCT.Count() > 300)) {
    2686           0 :                 LOG(("    removing empty connection entry\n"));
    2687           0 :                 iter.Remove();
    2688             :                 continue;
    2689           0 :             }
    2690           0 : 
    2691           0 :             // Otherwise use this opportunity to compact our arrays...
    2692           0 :             ent->mIdleConns.Compact();
    2693             :             ent->mActiveConns.Compact();
    2694             :             ent->mUrgentStartQ.Compact();
    2695             : 
    2696           0 :             for (auto it = ent->mPendingTransactionTable.Iter();
    2697             :                  !it.Done();
    2698             :                  it.Next()) {
    2699           0 :                 it.UserData()->Compact();
    2700             :             }
    2701           0 :         }
    2702           0 :     }
    2703             : }
    2704             : 
    2705           0 : void
    2706             : nsHttpConnectionMgr::OnMsgPruneNoTraffic(int32_t, ARefBase *)
    2707             : {
    2708           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2709             :     LOG(("nsHttpConnectionMgr::OnMsgPruneNoTraffic\n"));
    2710           0 : 
    2711             :     // Prune connections without traffic
    2712             :     for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
    2713           0 : 
    2714           0 :         // Close the connections with no registered traffic.
    2715             :         RefPtr<nsConnectionEntry> ent = iter.Data();
    2716           0 : 
    2717           0 :         LOG(("  pruning no traffic [ci=%s]\n",
    2718           0 :              ent->mConnInfo->HashKey().get()));
    2719           0 : 
    2720           0 :         uint32_t numConns = ent->mActiveConns.Length();
    2721           0 :         if (numConns) {
    2722           0 :             // Walk the list backwards to allow us to remove entries easily.
    2723             :             for (int index = numConns - 1; index >= 0; index--) {
    2724             :                 if (ent->mActiveConns[index]->NoTraffic()) {
    2725             :                     RefPtr<nsHttpConnection> conn = ent->mActiveConns[index];
    2726             :                     ent->mActiveConns.RemoveElementAt(index);
    2727             :                     DecrementActiveConnCount(conn);
    2728             :                     conn->Close(NS_ERROR_ABORT);
    2729           0 :                     LOG(("  closed active connection due to no traffic "
    2730           0 :                          "[conn=%p]\n", conn.get()));
    2731             :                 }
    2732             :             }
    2733           0 :         }
    2734             :     }
    2735           0 : 
    2736           0 :     mPruningNoTraffic = false; // not pruning anymore
    2737             : }
    2738           0 : 
    2739             : void
    2740             : nsHttpConnectionMgr::OnMsgVerifyTraffic(int32_t, ARefBase *)
    2741             : {
    2742             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2743             :     LOG(("nsHttpConnectionMgr::OnMsgVerifyTraffic\n"));
    2744             : 
    2745           0 :     if (mPruningNoTraffic) {
    2746           0 :       // Called in the time gap when the timeout to prune notraffic
    2747             :       // connections has triggered but the pruning hasn't happened yet.
    2748             :       return;
    2749           0 :     }
    2750           0 : 
    2751             :     // Mark connections for traffic verification
    2752             :     for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
    2753           0 :         RefPtr<nsConnectionEntry> ent = iter.Data();
    2754           0 : 
    2755             :         // Iterate over all active connections and check them.
    2756             :         for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
    2757             :             ent->mActiveConns[index]->CheckForTraffic(true);
    2758             :         }
    2759           0 :         // Iterate the idle connections and unmark them for traffic checks.
    2760           0 :         for (uint32_t index = 0; index < ent->mIdleConns.Length(); ++index) {
    2761             :             ent->mIdleConns[index]->CheckForTraffic(false);
    2762             :         }
    2763             :     }
    2764             : 
    2765           0 :     // If the timer is already there. we just re-init it
    2766             :     if(!mTrafficTimer) {
    2767             :         mTrafficTimer = NS_NewTimer();
    2768           0 :     }
    2769           0 : 
    2770             :     // failure to create a timer is not a fatal error, but dead
    2771           0 :     // connections will not be cleaned up as nicely
    2772             :     if (mTrafficTimer) {
    2773             :         // Give active connections time to get more traffic before killing
    2774             :         // them off. Default: 5000 milliseconds
    2775             :         mTrafficTimer->Init(this, gHttpHandler->NetworkChangedTimeout(),
    2776           0 :                             nsITimer::TYPE_ONE_SHOT);
    2777             :     } else {
    2778           0 :         NS_WARNING("failed to create timer for VerifyTraffic!");
    2779           0 :     }
    2780             : }
    2781           0 : 
    2782             : void
    2783           0 : nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup(int32_t, ARefBase *param)
    2784           0 : {
    2785             :     LOG(("nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup\n"));
    2786             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2787           0 : 
    2788           0 :     nsHttpConnectionInfo *ci = static_cast<nsHttpConnectionInfo *>(param);
    2789           0 : 
    2790             :     for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
    2791             :         ClosePersistentConnections(iter.Data());
    2792           0 :     }
    2793             : 
    2794           0 :     if (ci)
    2795             :         ResetIPFamilyPreference(ci);
    2796           0 : }
    2797             : 
    2798             : void
    2799             : nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, ARefBase *param)
    2800             : {
    2801             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2802             : 
    2803             :     nsHttpConnection *conn = static_cast<nsHttpConnection *>(param);
    2804           0 : 
    2805           0 :     //
    2806           0 :     // 1) remove the connection from the active list
    2807             :     // 2) if keep-alive, add connection to idle list
    2808           0 :     // 3) post event to process the pending transaction queue
    2809             :     //
    2810             : 
    2811             :     MOZ_ASSERT(conn);
    2812           0 :     nsConnectionEntry *ent = conn->ConnectionInfo() ?
    2813           0 :         mCT.GetWeak(conn->ConnectionInfo()->HashKey()) : nullptr;
    2814             : 
    2815             :     if (!ent) {
    2816             :         // this can happen if the connection is made outside of the
    2817             :         // connection manager and is being "reclaimed" for use with
    2818           0 :         // future transactions. HTTP/2 tunnels work like this.
    2819           0 :         ent = GetOrCreateConnectionEntry(conn->ConnectionInfo(), true);
    2820             :         LOG(("nsHttpConnectionMgr::OnMsgReclaimConnection conn %p "
    2821           0 :              "forced new hash entry %s\n",
    2822             :              conn, conn->ConnectionInfo()->HashKey().get()));
    2823             :     }
    2824             : 
    2825             :     MOZ_ASSERT(ent);
    2826             :     RefPtr<nsHttpConnectionInfo> ci(ent->mConnInfo);
    2827             : 
    2828           0 :     LOG(("nsHttpConnectionMgr::OnMsgReclaimConnection [ent=%p conn=%p]\n", ent, conn));
    2829             : 
    2830             :     // If the connection is in the active list, remove that entry
    2831             :     // and the reference held by the mActiveConns list.
    2832             :     // This is never the final reference on conn as the event context
    2833             :     // is also holding one that is released at the end of this function.
    2834             : 
    2835           0 :     if (conn->EverUsedSpdy()) {
    2836             :         // Spdy connections aren't reused in the traditional HTTP way in
    2837             :         // the idleconns list, they are actively multplexed as active
    2838             :         // conns. Even when they have 0 transactions on them they are
    2839             :         // considered active connections. So when one is reclaimed it
    2840             :         // is really complete and is meant to be shut down and not
    2841           0 :         // reused.
    2842           0 :         conn->DontReuse();
    2843             :     }
    2844             : 
    2845           0 :     // a connection that still holds a reference to a transaction was
    2846           0 :     // not closed naturally (i.e. it was reset or aborted) and is
    2847           0 :     // therefore not something that should be reused.
    2848             :     if (conn->Transaction()) {
    2849             :         conn->DontReuse();
    2850           0 :     }
    2851           0 : 
    2852             :     if (ent->mActiveConns.RemoveElement(conn)) {
    2853             :         DecrementActiveConnCount(conn);
    2854             :         ConditionallyStopTimeoutTick();
    2855             :     }
    2856             : 
    2857             :     if (conn->CanReuse()) {
    2858             :         LOG(("  adding connection to idle list\n"));
    2859             :         // Keep The idle connection list sorted with the connections that
    2860           0 :         // have moved the largest data pipelines at the front because these
    2861           0 :         // connections have the largest cwnds on the server.
    2862           0 : 
    2863             :         // The linear search is ok here because the number of idleconns
    2864             :         // in a single entry is generally limited to a small number (i.e. 6)
    2865             : 
    2866           0 :         uint32_t idx;
    2867           0 :         for (idx = 0; idx < ent->mIdleConns.Length(); idx++) {
    2868           0 :             nsHttpConnection *idleConn = ent->mIdleConns[idx];
    2869             :             if (idleConn->MaxBytesRead() < conn->MaxBytesRead())
    2870             :                 break;
    2871             :         }
    2872             : 
    2873           0 :         ent->mIdleConns.InsertElementAt(idx, conn);
    2874           0 :         mNumIdleConns++;
    2875           0 :         conn->BeginIdleMonitoring();
    2876             : 
    2877           0 :         // If the added connection was first idle connection or has shortest
    2878           0 :         // time to live among the watched connections, pruning dead
    2879             :         // connections needs to be done when it can't be reused anymore.
    2880             :         uint32_t timeToLive = conn->TimeToLive();
    2881           0 :         if(!mTimer || NowInSeconds() + timeToLive < mTimeOfNextWakeUp)
    2882           0 :             PruneDeadConnectionsAfter(timeToLive);
    2883             :     } else {
    2884             :         LOG(("  connection cannot be reused; closing connection\n"));
    2885           0 :         conn->Close(NS_ERROR_ABORT);
    2886             :     }
    2887           0 : 
    2888           0 :     OnMsgProcessPendingQ(0, ci);
    2889           0 : }
    2890             : 
    2891             : void
    2892             : nsHttpConnectionMgr::OnMsgCompleteUpgrade(int32_t, ARefBase *param)
    2893           0 : {
    2894           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2895           0 :     nsCompleteUpgradeData *data = static_cast<nsCompleteUpgradeData *>(param);
    2896             :     LOG(("nsHttpConnectionMgr::OnMsgCompleteUpgrade "
    2897             :          "this=%p conn=%p listener=%p\n", this, data->mConn.get(),
    2898           0 :          data->mUpgradeListener.get()));
    2899           0 : 
    2900           0 :     nsCOMPtr<nsISocketTransport> socketTransport;
    2901             :     nsCOMPtr<nsIAsyncInputStream> socketIn;
    2902           0 :     nsCOMPtr<nsIAsyncOutputStream> socketOut;
    2903           0 : 
    2904             :     nsresult rv;
    2905           0 :     rv = data->mConn->TakeTransport(getter_AddRefs(socketTransport),
    2906           0 :                                     getter_AddRefs(socketIn),
    2907           0 :                                     getter_AddRefs(socketOut));
    2908             : 
    2909             :     if (NS_SUCCEEDED(rv)) {
    2910             :         rv = data->mUpgradeListener->OnTransportAvailable(socketTransport,
    2911             :                                                           socketIn,
    2912           0 :                                                           socketOut);
    2913             :         if (NS_FAILED(rv)) {
    2914             :             LOG(("nsHttpConnectionMgr::OnMsgCompleteUpgrade "
    2915           0 :                  "this=%p conn=%p listener=%p\n", this, data->mConn.get(),
    2916             :                  data->mUpgradeListener.get()));
    2917           0 :         }
    2918           0 :     }
    2919           0 : }
    2920             : 
    2921           0 : void
    2922             : nsHttpConnectionMgr::OnMsgUpdateParam(int32_t inParam, ARefBase *)
    2923           0 : {
    2924           0 :     uint32_t param = static_cast<uint32_t>(inParam);
    2925             :     uint16_t name  = ((param) & 0xFFFF0000) >> 16;
    2926           0 :     uint16_t value =  param & 0x0000FFFF;
    2927           0 : 
    2928             :     switch (name) {
    2929           0 :     case MAX_CONNECTIONS:
    2930           0 :         mMaxConns = value;
    2931             :         break;
    2932           0 :     case MAX_URGENT_START_Q:
    2933           0 :         mMaxUrgentExcessiveConns = value;
    2934             :         break;
    2935           0 :     case MAX_PERSISTENT_CONNECTIONS_PER_HOST:
    2936           0 :         mMaxPersistConnsPerHost = value;
    2937             :         break;
    2938           0 :     case MAX_PERSISTENT_CONNECTIONS_PER_PROXY:
    2939           0 :         mMaxPersistConnsPerProxy = value;
    2940             :         break;
    2941           0 :     case MAX_REQUEST_DELAY:
    2942           0 :         mMaxRequestDelay = value;
    2943             :         break;
    2944           0 :     case THROTTLING_ENABLED:
    2945           0 :         SetThrottlingEnabled(!!value);
    2946             :         break;
    2947           0 :     case THROTTLING_SUSPEND_FOR:
    2948           0 :         mThrottleSuspendFor = value;
    2949             :         break;
    2950           0 :     case THROTTLING_RESUME_FOR:
    2951           0 :         mThrottleResumeFor = value;
    2952             :         break;
    2953           0 :     case THROTTLING_READ_LIMIT:
    2954           0 :         mThrottleReadLimit = value;
    2955             :         break;
    2956           0 :     case THROTTLING_READ_INTERVAL:
    2957           0 :         mThrottleReadInterval = value;
    2958             :         break;
    2959           0 :     case THROTTLING_HOLD_TIME:
    2960             :         mThrottleHoldTime = value;
    2961           0 :         break;
    2962             :     case THROTTLING_MAX_TIME:
    2963             :         mThrottleMaxTime = TimeDuration::FromMilliseconds(value);
    2964           0 :         break;
    2965             :     default:
    2966           0 :         NS_NOTREACHED("unexpected parameter name");
    2967             :     }
    2968           0 : }
    2969           0 : 
    2970           0 : // nsHttpConnectionMgr::nsConnectionEntry
    2971           0 : nsHttpConnectionMgr::nsConnectionEntry::~nsConnectionEntry()
    2972           0 : {
    2973           0 :     LOG(("nsConnectionEntry::~nsConnectionEntry this=%p", this));
    2974           0 : 
    2975             :     MOZ_ASSERT(!mIdleConns.Length());
    2976           0 :     MOZ_ASSERT(!mActiveConns.Length());
    2977           0 :     MOZ_ASSERT(!mHalfOpens.Length());
    2978             :     MOZ_ASSERT(!mUrgentStartQ.Length());
    2979             :     MOZ_ASSERT(!PendingQLength());
    2980             :     MOZ_ASSERT(!mHalfOpenFastOpenBackups.Length());
    2981             :     MOZ_ASSERT(!mDoNotDestroy);
    2982           0 : 
    2983             :     MOZ_COUNT_DTOR(nsConnectionEntry);
    2984           0 : }
    2985           0 : 
    2986             : // Read Timeout Tick handlers
    2987             : 
    2988             : void
    2989             : nsHttpConnectionMgr::ActivateTimeoutTick()
    2990             : {
    2991             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    2992           0 :     LOG(("nsHttpConnectionMgr::ActivateTimeoutTick() "
    2993             :          "this=%p mTimeoutTick=%p\n", this, mTimeoutTick.get()));
    2994           0 : 
    2995           0 :     // The timer tick should be enabled if it is not already pending.
    2996           0 :     // Upon running the tick will rearm itself if there are active
    2997             :     // connections available.
    2998             : 
    2999             :     if (mTimeoutTick && mTimeoutTickArmed) {
    3000             :         // make sure we get one iteration on a quick tick
    3001           0 :         if (mTimeoutTickNext > 1) {
    3002           0 :             mTimeoutTickNext = 1;
    3003           0 :             mTimeoutTick->SetDelay(1000);
    3004           0 :         }
    3005           0 :         return;
    3006             :     }
    3007           0 : 
    3008             :     if (!mTimeoutTick) {
    3009             :         mTimeoutTick = NS_NewTimer();
    3010           0 :         if (!mTimeoutTick) {
    3011           0 :             NS_WARNING("failed to create timer for http timeout management");
    3012           0 :             return;
    3013             :         }
    3014             :         mTimeoutTick->SetTarget(mSocketThreadTarget);
    3015             :     }
    3016             : 
    3017             :     MOZ_ASSERT(!mTimeoutTickArmed, "timer tick armed");
    3018           0 :     mTimeoutTickArmed = true;
    3019           0 :     mTimeoutTick->Init(this, 1000, nsITimer::TYPE_REPEATING_SLACK);
    3020             : }
    3021             : 
    3022             : class UINT64Wrapper : public ARefBase
    3023             : {
    3024             : public:
    3025             :     explicit UINT64Wrapper(uint64_t aUint64) : mUint64(aUint64) {}
    3026             :     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(UINT64Wrapper, override)
    3027           0 : 
    3028             :     uint64_t GetValue()
    3029             :     {
    3030             :         return mUint64;
    3031           0 :     }
    3032             : private:
    3033             :     uint64_t mUint64;
    3034           0 :     virtual ~UINT64Wrapper() = default;
    3035           0 : };
    3036             : 
    3037             : nsresult
    3038           0 : nsHttpConnectionMgr::UpdateCurrentTopLevelOuterContentWindowId(
    3039             :     uint64_t aWindowId)
    3040             : {
    3041           0 :     RefPtr<UINT64Wrapper> windowIdWrapper = new UINT64Wrapper(aWindowId);
    3042             :     return PostEvent(
    3043           0 :         &nsHttpConnectionMgr::OnMsgUpdateCurrentTopLevelOuterContentWindowId,
    3044             :         0,
    3045           0 :         windowIdWrapper);
    3046             : }
    3047           0 : 
    3048           0 : void nsHttpConnectionMgr::SetThrottlingEnabled(bool aEnable)
    3049             : {
    3050           0 :     LOG(("nsHttpConnectionMgr::SetThrottlingEnabled enable=%d", aEnable));
    3051           0 : 
    3052           0 :     mThrottleEnabled = aEnable;
    3053             : 
    3054           0 :     if (mThrottleEnabled) {
    3055             :         EnsureThrottleTickerIfNeeded();
    3056           0 :     } else {
    3057             :         DestroyThrottleTicker();
    3058           0 :         ResumeReadOf(mActiveTransactions[false]);
    3059             :         ResumeReadOf(mActiveTransactions[true]);
    3060           0 :     }
    3061             : }
    3062             : 
    3063           0 : bool nsHttpConnectionMgr::InThrottlingTimeWindow()
    3064             : {
    3065             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    3066           0 : 
    3067             :     if (mThrottlingWindowEndsAt.IsNull()) {
    3068           0 :         return true;
    3069             :     }
    3070           0 :     return TimeStamp::NowLoRes() <= mThrottlingWindowEndsAt;
    3071             : }
    3072           0 : 
    3073             : void nsHttpConnectionMgr::TouchThrottlingTimeWindow(bool aEnsureTicker)
    3074           0 : {
    3075           0 :     LOG(("nsHttpConnectionMgr::TouchThrottlingTimeWindow"));
    3076           0 : 
    3077             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    3078           0 : 
    3079             :     mThrottlingWindowEndsAt = TimeStamp::NowLoRes() + mThrottleMaxTime;
    3080           0 : 
    3081             :     if (!mThrottleTicker &&
    3082           0 :         MOZ_LIKELY(aEnsureTicker) && MOZ_LIKELY(mThrottleEnabled)) {
    3083             :         EnsureThrottleTickerIfNeeded();
    3084             :     }
    3085             : }
    3086           0 : 
    3087           0 : void nsHttpConnectionMgr::LogActiveTransactions(char operation)
    3088             : {
    3089           0 :     if (!LOG_ENABLED()) {
    3090           0 :         return;
    3091           0 :     }
    3092           0 : 
    3093             :     nsTArray<RefPtr<nsHttpTransaction>> *trs = nullptr;
    3094           0 :     uint32_t au, at, bu = 0, bt = 0;
    3095           0 : 
    3096             :     trs = mActiveTransactions[false].Get(mCurrentTopLevelOuterContentWindowId);
    3097           0 :     au = trs ? trs->Length() : 0;
    3098           0 :     trs = mActiveTransactions[true].Get(mCurrentTopLevelOuterContentWindowId);
    3099           0 :     at = trs ? trs->Length() : 0;
    3100             : 
    3101           0 :     for (auto iter = mActiveTransactions[false].Iter(); !iter.Done(); iter.Next()) {
    3102             :         bu += iter.UserData()->Length();
    3103             :     }
    3104             :     bu -= au;
    3105             :     for (auto iter = mActiveTransactions[true].Iter(); !iter.Done(); iter.Next()) {
    3106             :         bt += iter.UserData()->Length();
    3107             :     }
    3108           0 :     bt -= at;
    3109             : 
    3110             :     // Shows counts of:
    3111             :     // - unthrottled transaction for the active tab
    3112           0 :     // - throttled transaction for the active tab
    3113             :     // - unthrottled transaction for background tabs
    3114           0 :     // - throttled transaction for background tabs
    3115             :     LOG(("Active transactions %c[%u,%u,%u,%u]", operation, au, at, bu, bt));
    3116           0 : }
    3117           0 : 
    3118             : void
    3119             : nsHttpConnectionMgr::AddActiveTransaction(nsHttpTransaction * aTrans)
    3120           0 : {
    3121             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    3122           0 : 
    3123             :     uint64_t tabId = aTrans->TopLevelOuterContentWindowId();
    3124           0 :     bool throttled = aTrans->EligibleForThrottling();
    3125             : 
    3126           0 :     nsTArray<RefPtr<nsHttpTransaction>> *transactions =
    3127             :         mActiveTransactions[throttled].LookupOrAdd(tabId);
    3128           0 : 
    3129             :     MOZ_ASSERT(!transactions->Contains(aTrans));
    3130           0 : 
    3131           0 :     transactions->AppendElement(aTrans);
    3132           0 : 
    3133           0 :     LOG(("nsHttpConnectionMgr::AddActiveTransaction    t=%p tabid=%" PRIx64 "(%d) thr=%d",
    3134             :           aTrans, tabId, tabId == mCurrentTopLevelOuterContentWindowId, throttled));
    3135             :     LogActiveTransactions('+');
    3136             : 
    3137             :     if (tabId == mCurrentTopLevelOuterContentWindowId) {
    3138             :         mActiveTabTransactionsExist = true;
    3139             :         if (!throttled) {
    3140             :             mActiveTabUnthrottledTransactionsExist = true;
    3141             :         }
    3142             :     }
    3143           0 : 
    3144             :     // Shift the throttling window to the future (actually, makes sure
    3145           0 :     // that throttling will engage when there is anything to throttle.)
    3146           0 :     // The |false| argument means we don't need this call to ensure
    3147             :     // the ticker, since we do it just below.  Calling
    3148             :     // EnsureThrottleTickerIfNeeded directly does a bit more than call
    3149           0 :     // from inside of TouchThrottlingTimeWindow.
    3150             :     TouchThrottlingTimeWindow(false);
    3151             : 
    3152             :     if (!mThrottleEnabled) {
    3153           0 :         return;
    3154             :     }
    3155             : 
    3156           0 :     EnsureThrottleTickerIfNeeded();
    3157             : }
    3158           0 : 
    3159           0 : void
    3160           0 : nsHttpConnectionMgr::RemoveActiveTransaction(nsHttpTransaction * aTrans,
    3161             :                                              Maybe<bool> const& aOverride)
    3162             : {
    3163           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    3164             : 
    3165           0 :     uint64_t tabId = aTrans->TopLevelOuterContentWindowId();
    3166             :     bool forActiveTab = tabId == mCurrentTopLevelOuterContentWindowId;
    3167           0 :     bool throttled = aOverride.valueOr(aTrans->EligibleForThrottling());
    3168             : 
    3169             :     nsTArray<RefPtr<nsHttpTransaction>> *transactions =
    3170           0 :         mActiveTransactions[throttled].Get(tabId);
    3171             : 
    3172             :     if (!transactions || !transactions->RemoveElement(aTrans)) {
    3173           0 :         // Was not tracked as active, probably just ignore.
    3174             :         return;
    3175             :     }
    3176             : 
    3177           0 :     LOG(("nsHttpConnectionMgr::RemoveActiveTransaction t=%p tabid=%" PRIx64 "(%d) thr=%d",
    3178           0 :           aTrans, tabId, forActiveTab, throttled));
    3179             : 
    3180             :     if (!transactions->IsEmpty()) {
    3181             :         // There are still transactions of the type, hence nothing in the throttling conditions
    3182           0 :         // has changed and we don't need to update "Exists" caches nor we need to wake any now
    3183           0 :         // throttled transactions.
    3184             :         LogActiveTransactions('-');
    3185           0 :         return;
    3186             :     }
    3187           0 : 
    3188           0 :     // To optimize the following logic, always remove the entry when the array is empty.
    3189             :     mActiveTransactions[throttled].Remove(tabId);
    3190           0 :     LogActiveTransactions('-');
    3191           0 : 
    3192             :     if (forActiveTab) {
    3193             :         // Update caches of the active tab transaction existence, since it's now affected
    3194             :         if (!throttled) {
    3195           0 :             mActiveTabUnthrottledTransactionsExist = false;
    3196             :         }
    3197             :         if (mActiveTabTransactionsExist) {
    3198             :             mActiveTabTransactionsExist = mActiveTransactions[!throttled].Contains(tabId);
    3199           0 :         }
    3200           0 :     }
    3201             : 
    3202           0 :     if (!mThrottleEnabled) {
    3203             :         return;
    3204           0 :     }
    3205           0 : 
    3206             :     bool unthrottledExist = !mActiveTransactions[false].IsEmpty();
    3207           0 :     bool throttledExist = !mActiveTransactions[true].IsEmpty();
    3208           0 : 
    3209             :     if (!unthrottledExist && !throttledExist) {
    3210             :         // Nothing active globally, just get rid of the timer completely and we are done.
    3211           0 :         MOZ_ASSERT(!mActiveTabUnthrottledTransactionsExist);
    3212           0 :         MOZ_ASSERT(!mActiveTabTransactionsExist);
    3213             : 
    3214             :         DestroyThrottleTicker();
    3215           0 :         return;
    3216             :     }
    3217             : 
    3218             :     if (mThrottleVersion == 1) {
    3219             :         if (!mThrottlingInhibitsReading) {
    3220           0 :             // There is then nothing to wake up.  Affected transactions will not be put
    3221             :             // to sleep automatically on next tick.
    3222             :             LOG(("  reading not currently inhibited"));
    3223           0 :             return;
    3224             :         }
    3225             :     }
    3226             : 
    3227           0 :     if (mActiveTabUnthrottledTransactionsExist) {
    3228             :         // There are still unthrottled transactions for the active tab, hence the state
    3229             :         // is unaffected and we don't need to do anything (nothing to wake).
    3230             :         LOG(("  there are unthrottled for the active tab"));
    3231           0 :         return;
    3232           0 :     }
    3233           0 : 
    3234             :     if (mActiveTabTransactionsExist) {
    3235             :         // There are only trottled transactions for the active tab.
    3236             :         // If the last transaction we just removed was a non-throttled for the active tab
    3237             :         // we can wake the throttled transactions for the active tab.
    3238           0 :         if (forActiveTab && !throttled) {
    3239             :             LOG(("  resuming throttled for active tab"));
    3240             :             ResumeReadOf(mActiveTransactions[true].Get(mCurrentTopLevelOuterContentWindowId));
    3241           0 :         }
    3242           0 :         return;
    3243           0 :     }
    3244             : 
    3245             :     if (!unthrottledExist) {
    3246           0 :         // There are no unthrottled transactions for any tab.  Resume all throttled,
    3247             :         // all are only for background tabs.
    3248             :         LOG(("  delay resuming throttled for background tabs"));
    3249           0 :         DelayedResumeBackgroundThrottledTransactions();
    3250           0 :         return;
    3251           0 :     }
    3252             : 
    3253             :     if (forActiveTab) {
    3254           0 :         // Removing the last transaction for the active tab frees up the unthrottled
    3255             :         // background tabs transactions.
    3256             :         LOG(("  delay resuming unthrottled for background tabs"));
    3257             :         DelayedResumeBackgroundThrottledTransactions();
    3258           0 :         return;
    3259             :     }
    3260           0 : 
    3261             :     LOG(("  not resuming anything"));
    3262             : }
    3263             : 
    3264             : void
    3265             : nsHttpConnectionMgr::UpdateActiveTransaction(nsHttpTransaction * aTrans)
    3266             : {
    3267             :     LOG(("nsHttpConnectionMgr::UpdateActiveTransaction ENTER t=%p", aTrans));
    3268           0 : 
    3269           0 :     // First remove then add.  In case of a download that is the only active
    3270           0 :     // transaction and has just been marked as download (goes unthrottled to
    3271             :     // throttled), adding first would cause it to be throttled for first few
    3272           0 :     // milliseconds - becuause it would appear as if there were both throttled
    3273             :     // and unthrottled transactions at the time.
    3274           0 : 
    3275           0 :     Maybe<bool> reversed;
    3276             :     reversed.emplace(!aTrans->EligibleForThrottling());
    3277             :     RemoveActiveTransaction(aTrans, reversed);
    3278           0 : 
    3279             :     AddActiveTransaction(aTrans);
    3280           0 : 
    3281             :     LOG(("nsHttpConnectionMgr::UpdateActiveTransaction EXIT t=%p", aTrans));
    3282           0 : }
    3283             : 
    3284           0 : bool
    3285           0 : nsHttpConnectionMgr::ShouldThrottle(nsHttpTransaction * aTrans)
    3286             : {
    3287             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    3288             : 
    3289           0 :     LOG(("nsHttpConnectionMgr::ShouldThrottle trans=%p", aTrans));
    3290             : 
    3291             :     if (mThrottleVersion == 1) {
    3292             :         if (!mThrottlingInhibitsReading || !mThrottleEnabled) {
    3293             :             return false;
    3294           0 :         }
    3295           0 :     } else {
    3296           0 :         if (!mThrottleEnabled) {
    3297             :             return false;
    3298           0 :         }
    3299           0 :     }
    3300           0 : 
    3301             :     uint64_t tabId = aTrans->TopLevelOuterContentWindowId();
    3302             :     bool forActiveTab = tabId == mCurrentTopLevelOuterContentWindowId;
    3303             :     bool throttled = aTrans->EligibleForThrottling();
    3304           0 : 
    3305           0 :     bool stop = [=]() {
    3306             :         if (mActiveTabTransactionsExist) {
    3307           0 :             if (!tabId) {
    3308             :                 // Chrome initiated and unidentified transactions just respect
    3309             :                 // their throttle flag, when something for the active tab is happening.
    3310           0 :                 // This also includes downloads.
    3311             :                 LOG(("  active tab loads, trans is tab-less, throttled=%d", throttled));
    3312             :                 return throttled;
    3313             :             }
    3314           0 :             if (!forActiveTab) {
    3315             :                 // This is a background tab request, we want them to always throttle
    3316           0 :                 // when there are transactions running for the ative tab.
    3317           0 :                 LOG(("  active tab loads, trans not of the active tab"));
    3318             :                 return true;
    3319             :             }
    3320           0 : 
    3321             :             if (mActiveTabUnthrottledTransactionsExist) {
    3322             :                 // Unthrottled transactions for the active tab take precedence
    3323             :                 LOG(("  active tab loads unthrottled, trans throttled=%d", throttled));
    3324           0 :                 return throttled;
    3325             :             }
    3326           0 : 
    3327             :             LOG(("  trans for active tab, don't throttle"));
    3328             :             return false;
    3329             :         }
    3330             : 
    3331           0 :         MOZ_ASSERT(!forActiveTab);
    3332           0 : 
    3333             :         if (!mActiveTransactions[false].IsEmpty()) {
    3334             :             // This means there are unthrottled active transactions for background tabs.
    3335             :             // If we are here, there can't be any transactions for the active tab.
    3336           0 :             // (If there is no transaction for a tab id, there is no entry for it in
    3337             :             // the hashtable.)
    3338           0 :             LOG(("  backround tab(s) load unthrottled, trans throttled=%d", throttled));
    3339             :             return throttled;
    3340           0 :         }
    3341             : 
    3342             :         // There are only unthrottled transactions for background tabs: don't throttle.
    3343             :         LOG(("  backround tab(s) load throttled, don't throttle"));
    3344           0 :         return false;
    3345           0 :     }();
    3346             : 
    3347             :     if (forActiveTab && !stop) {
    3348             :         // This is an active-tab transaction and is allowed to read.  Hence,
    3349             :         // prolong the throttle time window to make sure all 'lower-decks'
    3350             :         // transactions will actually throttle.
    3351             :         TouchThrottlingTimeWindow();
    3352           0 :         return false;
    3353             :     }
    3354           0 : 
    3355             :     // Only stop reading when in the configured throttle max-time (aka time window).
    3356             :     // This window is prolonged (restarted) by a call to TouchThrottlingTimeWindow
    3357           0 :     // called on new transaction activation or on receive of response bytes of an
    3358             :     // active tab transaction.
    3359             :     bool inWindow = InThrottlingTimeWindow();
    3360           0 : 
    3361             :     LOG(("  stop=%d, in-window=%d, delayed-bck-timer=%d",
    3362             :          stop, inWindow, !!mDelayedResumeReadTimer));
    3363           0 : 
    3364             :     if (!forActiveTab) {
    3365             :         // If the delayed background resume timer exists, background transactions are
    3366           0 :         // scheduled to be woken after a delay, hence leave them throttled.
    3367             :         inWindow = inWindow || mDelayedResumeReadTimer;
    3368           0 :     }
    3369           0 : 
    3370             :     return stop && inWindow;
    3371             : }
    3372             : 
    3373             : bool nsHttpConnectionMgr::IsConnEntryUnderPressure(nsHttpConnectionInfo *connInfo)
    3374             : {
    3375           0 :     nsConnectionEntry *ent = mCT.GetWeak(connInfo->HashKey());
    3376             :     if (!ent) {
    3377           0 :       // No entry, no pressure.
    3378             :       return false;
    3379             :     }
    3380           0 : 
    3381             :     nsTArray<RefPtr<PendingTransactionInfo>> *transactions =
    3382           0 :         ent->mPendingTransactionTable.Get(mCurrentTopLevelOuterContentWindowId);
    3383             : 
    3384           0 :     return transactions && !transactions->IsEmpty();
    3385           0 : }
    3386           0 : 
    3387             : bool nsHttpConnectionMgr::IsThrottleTickerNeeded()
    3388             : {
    3389             :     LOG(("nsHttpConnectionMgr::IsThrottleTickerNeeded"));
    3390           0 : 
    3391           0 :     if (mActiveTabUnthrottledTransactionsExist &&
    3392           0 :         mActiveTransactions[false].Count() > 1) {
    3393             :         LOG(("  there are unthrottled transactions for both active and bck"));
    3394             :         return true;
    3395             :     }
    3396           0 : 
    3397           0 :     if (mActiveTabTransactionsExist &&
    3398           0 :         mActiveTransactions[true].Count() > 1) {
    3399             :         LOG(("  there are throttled transactions for both active and bck"));
    3400             :         return true;
    3401             :     }
    3402           0 : 
    3403             :     if (!mActiveTransactions[true].IsEmpty() &&
    3404             :         !mActiveTransactions[false].IsEmpty()) {
    3405             :         LOG(("  there are both throttled and unthrottled transactions"));
    3406             :         return true;
    3407           0 :     }
    3408             : 
    3409           0 :     LOG(("  nothing to throttle"));
    3410             :     return false;
    3411           0 : }
    3412           0 : 
    3413             : void
    3414             : nsHttpConnectionMgr::EnsureThrottleTickerIfNeeded()
    3415             : {
    3416             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    3417             : 
    3418           0 :     LOG(("nsHttpConnectionMgr::EnsureThrottleTickerIfNeeded"));
    3419             :     if (!IsThrottleTickerNeeded()) {
    3420           0 :         return;
    3421             :     }
    3422             : 
    3423             :     // There is a new demand to throttle, hence unschedule delayed resume
    3424           0 :     // of background throttled transastions.
    3425           0 :     CancelDelayedResumeBackgroundThrottledTransactions();
    3426           0 : 
    3427           0 :     if (mThrottleTicker) {
    3428             :         return;
    3429           0 :     }
    3430           0 : 
    3431             :     mThrottleTicker = NS_NewTimer();
    3432           0 :     if (mThrottleTicker) {
    3433             :         if (mThrottleVersion == 1) {
    3434             :             MOZ_ASSERT(!mThrottlingInhibitsReading);
    3435             : 
    3436           0 :             mThrottleTicker->Init(this, mThrottleSuspendFor, nsITimer::TYPE_ONE_SHOT);
    3437             :             mThrottlingInhibitsReading = true;
    3438             :         } else {
    3439             :             mThrottleTicker->Init(this, mThrottleReadInterval, nsITimer::TYPE_ONE_SHOT);
    3440           0 :         }
    3441             :     }
    3442           0 : 
    3443             :     LogActiveTransactions('^');
    3444             : }
    3445           0 : 
    3446             : void
    3447           0 : nsHttpConnectionMgr::DestroyThrottleTicker()
    3448             : {
    3449           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    3450             : 
    3451             :     // Nothing to throttle, hence no need for this timer anymore.
    3452             :     CancelDelayedResumeBackgroundThrottledTransactions();
    3453           0 : 
    3454           0 :     MOZ_ASSERT(!mThrottleEnabled || !IsThrottleTickerNeeded());
    3455           0 : 
    3456             :     if (!mThrottleTicker) {
    3457           0 :         return;
    3458           0 :     }
    3459             : 
    3460             :     LOG(("nsHttpConnectionMgr::DestroyThrottleTicker"));
    3461           0 :     mThrottleTicker->Cancel();
    3462             :     mThrottleTicker = nullptr;
    3463             : 
    3464             :     if (mThrottleVersion == 1) {
    3465           0 :         mThrottlingInhibitsReading = false;
    3466             :     }
    3467           0 : 
    3468             :     LogActiveTransactions('v');
    3469           0 : }
    3470           0 : 
    3471             : void
    3472           0 : nsHttpConnectionMgr::ThrottlerTick()
    3473             : {
    3474             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    3475             : 
    3476             :     if (mThrottleVersion == 1) {
    3477           0 :         mThrottlingInhibitsReading = !mThrottlingInhibitsReading;
    3478           0 : 
    3479           0 :         LOG(("nsHttpConnectionMgr::ThrottlerTick inhibit=%d", mThrottlingInhibitsReading));
    3480           0 : 
    3481           0 :         // If there are only background transactions to be woken after a delay, keep
    3482             :         // the ticker so that we woke them only for the resume-for interval and then
    3483             :         // throttle them again until the background-resume delay passes.
    3484           0 :         if (!mThrottlingInhibitsReading &&
    3485           0 :             !mDelayedResumeReadTimer &&
    3486           0 :             (!IsThrottleTickerNeeded() || !InThrottlingTimeWindow())) {
    3487             :             LOG(("  last tick"));
    3488             :             mThrottleTicker = nullptr;
    3489           0 :         }
    3490           0 : 
    3491             :         if (mThrottlingInhibitsReading) {
    3492             :             if (mThrottleTicker) {
    3493           0 :                 mThrottleTicker->Init(this, mThrottleSuspendFor, nsITimer::TYPE_ONE_SHOT);
    3494           0 :             }
    3495             :         } else {
    3496             :             if (mThrottleTicker) {
    3497           0 :                 mThrottleTicker->Init(this, mThrottleResumeFor, nsITimer::TYPE_ONE_SHOT);
    3498             :             }
    3499             : 
    3500             :             ResumeReadOf(mActiveTransactions[false], true);
    3501           0 :             ResumeReadOf(mActiveTransactions[true]);
    3502           0 :         }
    3503           0 :     } else {
    3504           0 :         LOG(("nsHttpConnectionMgr::ThrottlerTick"));
    3505             : 
    3506             :         // If there are only background transactions to be woken after a delay, keep
    3507           0 :         // the ticker so that we still keep the low read limit for that time.
    3508           0 :         if (!mDelayedResumeReadTimer &&
    3509             :             (!IsThrottleTickerNeeded() || !InThrottlingTimeWindow())) {
    3510             :             LOG(("  last tick"));
    3511           0 :             mThrottleTicker = nullptr;
    3512           0 :         }
    3513             : 
    3514           0 :         if (mThrottleTicker) {
    3515             :             mThrottleTicker->Init(this, mThrottleReadInterval, nsITimer::TYPE_ONE_SHOT);
    3516             :         }
    3517           0 : 
    3518             :         ResumeReadOf(mActiveTransactions[false], true);
    3519           0 :         ResumeReadOf(mActiveTransactions[true]);
    3520             :     }
    3521           0 : }
    3522           0 : 
    3523             : void
    3524             : nsHttpConnectionMgr::DelayedResumeBackgroundThrottledTransactions()
    3525             : {
    3526             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    3527             : 
    3528             :     if (mThrottleVersion == 1) {
    3529             :         if (mDelayedResumeReadTimer) {
    3530           0 :             return;
    3531             :         }
    3532             :     } else {
    3533             :         // If the mThrottleTicker doesn't exist, there is nothing currently
    3534             :         // being throttled.  Hence, don't invoke the hold time interval.
    3535           0 :         // This is called also when a single download transaction becomes
    3536           0 :         // marked as throttleable.  We would otherwise block it unnecessarily.
    3537           0 :         if (mDelayedResumeReadTimer || !mThrottleTicker) {
    3538             :             return;
    3539             :         }
    3540             :     }
    3541           0 : 
    3542             :     LOG(("nsHttpConnectionMgr::DelayedResumeBackgroundThrottledTransactions"));
    3543           0 :     NS_NewTimerWithObserver(getter_AddRefs(mDelayedResumeReadTimer),
    3544             :                             this, mThrottleHoldTime, nsITimer::TYPE_ONE_SHOT);
    3545             : }
    3546             : 
    3547           0 : void
    3548           0 : nsHttpConnectionMgr::CancelDelayedResumeBackgroundThrottledTransactions()
    3549           0 : {
    3550             :     if (!mDelayedResumeReadTimer) {
    3551             :         return;
    3552             :     }
    3553           0 : 
    3554             :     LOG(("nsHttpConnectionMgr::CancelDelayedResumeBackgroundThrottledTransactions"));
    3555           0 :     mDelayedResumeReadTimer->Cancel();
    3556             :     mDelayedResumeReadTimer = nullptr;
    3557           0 : }
    3558           0 : 
    3559             : void
    3560           0 : nsHttpConnectionMgr::ResumeBackgroundThrottledTransactions()
    3561           0 : {
    3562             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    3563             : 
    3564           0 :     LOG(("nsHttpConnectionMgr::ResumeBackgroundThrottledTransactions"));
    3565           0 :     mDelayedResumeReadTimer = nullptr;
    3566             : 
    3567           0 :     if (!IsThrottleTickerNeeded()) {
    3568             :         DestroyThrottleTicker();
    3569           0 :     }
    3570             : 
    3571             :     if (!mActiveTransactions[false].IsEmpty()) {
    3572           0 :         ResumeReadOf(mActiveTransactions[false], true);
    3573             :     } else {
    3574             :         ResumeReadOf(mActiveTransactions[true], true);
    3575             :     }
    3576           0 : }
    3577           0 : 
    3578             : void
    3579             : nsHttpConnectionMgr::ResumeReadOf(
    3580             :     nsClassHashtable<nsUint64HashKey, nsTArray<RefPtr<nsHttpTransaction>>>& hashtable,
    3581           0 :     bool excludeForActiveTab)
    3582             : {
    3583           0 :     for (auto iter = hashtable.Iter(); !iter.Done(); iter.Next()) {
    3584             :         if (excludeForActiveTab && iter.Key() == mCurrentTopLevelOuterContentWindowId) {
    3585             :             // These have never been throttled (never stopped reading)
    3586           0 :             continue;
    3587             :         }
    3588           0 :         ResumeReadOf(iter.UserData());
    3589             :     }
    3590           0 : }
    3591           0 : 
    3592             : void
    3593           0 : nsHttpConnectionMgr::ResumeReadOf(nsTArray<RefPtr<nsHttpTransaction>>* transactions)
    3594             : {
    3595             :     MOZ_ASSERT(transactions);
    3596           0 : 
    3597             :     for (const auto& trans : *transactions) {
    3598           0 :         trans->ResumeReading();
    3599             :     }
    3600           0 : }
    3601           0 : 
    3602             : void
    3603             : nsHttpConnectionMgr::NotifyConnectionOfWindowIdChange(uint64_t previousWindowId)
    3604           0 : {
    3605           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    3606             : 
    3607             :     nsTArray<RefPtr<nsHttpTransaction>> *transactions = nullptr;
    3608             :     nsTArray<RefPtr<nsAHttpConnection>> connections;
    3609           0 : 
    3610           0 :     auto addConnectionHelper =
    3611           0 :         [&connections](nsTArray<RefPtr<nsHttpTransaction>> *trans) {
    3612           0 :             if (!trans) {
    3613             :                 return;
    3614             :             }
    3615           0 : 
    3616             :             for (const auto& t : *trans) {
    3617             :                 RefPtr<nsAHttpConnection> conn = t->Connection();
    3618           0 :                 if (conn && !connections.Contains(conn)) {
    3619           0 :                     connections.AppendElement(conn);
    3620             :                 }
    3621           0 :             }
    3622           0 :         };
    3623             : 
    3624             :     // Get unthrottled transactions with the previous and current window id.
    3625           0 :     transactions = mActiveTransactions[false].Get(previousWindowId);
    3626           0 :     addConnectionHelper(transactions);
    3627             :     transactions =
    3628           0 :         mActiveTransactions[false].Get(mCurrentTopLevelOuterContentWindowId);
    3629           0 :     addConnectionHelper(transactions);
    3630             : 
    3631           0 :     // Get throttled transactions with the previous and current window id.
    3632           0 :     transactions = mActiveTransactions[true].Get(previousWindowId);
    3633             :     addConnectionHelper(transactions);
    3634           0 :     transactions =
    3635             :         mActiveTransactions[true].Get(mCurrentTopLevelOuterContentWindowId);
    3636             :     addConnectionHelper(transactions);
    3637           0 : 
    3638             :     for (const auto& conn : connections) {
    3639             :         conn->TopLevelOuterContentWindowIdChanged(mCurrentTopLevelOuterContentWindowId);
    3640           0 :     }
    3641             : }
    3642           0 : 
    3643             : void
    3644           0 : nsHttpConnectionMgr::OnMsgUpdateCurrentTopLevelOuterContentWindowId(
    3645             :     int32_t aLoading, ARefBase *param)
    3646             : {
    3647             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    3648             : 
    3649           0 :     uint64_t winId = static_cast<UINT64Wrapper*>(param)->GetValue();
    3650             : 
    3651           0 :     if (mCurrentTopLevelOuterContentWindowId == winId) {
    3652           0 :         // duplicate notification
    3653             :         return;
    3654           0 :     }
    3655           0 : 
    3656             :     bool activeTabWasLoading = mActiveTabTransactionsExist;
    3657             : 
    3658           0 :     uint64_t previousWindowId = mCurrentTopLevelOuterContentWindowId;
    3659             :     mCurrentTopLevelOuterContentWindowId = winId;
    3660             : 
    3661             :     if (gHttpHandler->ActiveTabPriority()) {
    3662           0 :         NotifyConnectionOfWindowIdChange(previousWindowId);
    3663             :     }
    3664             : 
    3665             :     LOG(("nsHttpConnectionMgr::OnMsgUpdateCurrentTopLevelOuterContentWindowId"
    3666           0 :          " id=%" PRIx64 "\n",
    3667           0 :          mCurrentTopLevelOuterContentWindowId));
    3668             : 
    3669           0 :     nsTArray<RefPtr<nsHttpTransaction>> *transactions = nullptr;
    3670           0 : 
    3671             :     // Update the "Exists" caches and resume any transactions that now deserve it,
    3672           0 :     // changing the active tab changes the conditions for throttling.
    3673             :     transactions = mActiveTransactions[false].Get(mCurrentTopLevelOuterContentWindowId);
    3674           0 :     mActiveTabUnthrottledTransactionsExist = !!transactions;
    3675             : 
    3676             :     if (!mActiveTabUnthrottledTransactionsExist) {
    3677           0 :         transactions = mActiveTransactions[true].Get(mCurrentTopLevelOuterContentWindowId);
    3678           0 :     }
    3679           0 :     mActiveTabTransactionsExist = !!transactions;
    3680             : 
    3681             :     if (transactions) {
    3682           0 :         // This means there are some transactions for this newly activated tab, resume them
    3683             :         // but anything else.
    3684             :         LOG(("  resuming newly activated tab transactions"));
    3685             :         ResumeReadOf(transactions);
    3686             :         return;
    3687             :     }
    3688             : 
    3689           0 :     if (!activeTabWasLoading) {
    3690           0 :         // There were no transactions for the previously active tab, hence
    3691           0 :         // all remaning transactions, if there were, were all unthrottled,
    3692           0 :         // no need to wake them.
    3693             :         return;
    3694             :     }
    3695           0 : 
    3696           0 :     if (!mActiveTransactions[false].IsEmpty()) {
    3697           0 :         LOG(("  resuming unthrottled background transactions"));
    3698           0 :         ResumeReadOf(mActiveTransactions[false]);
    3699             :         return;
    3700             :     }
    3701           0 : 
    3702             :     if (!mActiveTransactions[true].IsEmpty()) {
    3703             :         LOG(("  resuming throttled background transactions"));
    3704             :         ResumeReadOf(mActiveTransactions[true]);
    3705           0 :         return;
    3706             :     }
    3707           0 : 
    3708           0 :     DestroyThrottleTicker();
    3709             : }
    3710           0 : 
    3711             : void
    3712             : nsHttpConnectionMgr::TimeoutTick()
    3713             : {
    3714           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    3715             :     MOZ_ASSERT(mTimeoutTick, "no readtimeout tick");
    3716           0 : 
    3717           0 :     LOG(("nsHttpConnectionMgr::TimeoutTick active=%d\n", mNumActiveConns));
    3718             :     // The next tick will be between 1 second and 1 hr
    3719           0 :     // Set it to the max value here, and the TimeoutTick()s can
    3720             :     // reduce it to their local needs.
    3721             :     mTimeoutTickNext = 3600; // 1hr
    3722             : 
    3723             :     for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
    3724             :         RefPtr<nsConnectionEntry> ent = iter.Data();
    3725             : 
    3726             :         LOG(("nsHttpConnectionMgr::TimeoutTick() this=%p host=%s "
    3727             :              "idle=%zu active=%zu"
    3728           0 :              " half-len=%zu pending=%zu"
    3729           0 :              " urgentStart pending=%zu\n",
    3730             :              this, ent->mConnInfo->Origin(), ent->mIdleConns.Length(),
    3731           0 :              ent->mActiveConns.Length(), ent->mHalfOpens.Length(),
    3732           0 :              ent->PendingQLength(), ent->mUrgentStartQ.Length()));
    3733             : 
    3734             :         // First call the tick handler for each active connection.
    3735             :         PRIntervalTime tickTime = PR_IntervalNow();
    3736           0 :         for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
    3737           0 :             uint32_t connNextTimeout =
    3738           0 :                 ent->mActiveConns[index]->ReadTimeoutTick(tickTime);
    3739             :             mTimeoutTickNext = std::min(mTimeoutTickNext, connNextTimeout);
    3740           0 :         }
    3741           0 : 
    3742             :         // Now check for any stalled half open sockets.
    3743           0 :         if (ent->mHalfOpens.Length()) {
    3744           0 :             TimeStamp currentTime = TimeStamp::Now();
    3745             :             double maxConnectTime_ms = gHttpHandler->ConnectTimeout();
    3746             : 
    3747           0 :             for (uint32_t index = ent->mHalfOpens.Length(); index > 0; ) {
    3748           0 :                 index--;
    3749             : 
    3750           0 :                 nsHalfOpenSocket *half = ent->mHalfOpens[index];
    3751           0 :                 double delta = half->Duration(currentTime);
    3752             :                 // If the socket has timed out, close it so the waiting
    3753           0 :                 // transaction will get the proper signal.
    3754           0 :                 if (delta > maxConnectTime_ms) {
    3755             :                     LOG(("Force timeout of half open to %s after %.2fms.\n",
    3756             :                          ent->mConnInfo->HashKey().get(), delta));
    3757             :                     if (half->SocketTransport()) {
    3758             :                         half->SocketTransport()->Close(NS_ERROR_NET_TIMEOUT);
    3759             :                     }
    3760           0 :                     if (half->BackupTransport()) {
    3761           0 :                         half->BackupTransport()->Close(NS_ERROR_NET_TIMEOUT);
    3762             :                     }
    3763           0 :                 }
    3764             : 
    3765             :                 // If this half open hangs around for 5 seconds after we've
    3766             :                 // closed() it then just abandon the socket.
    3767           0 :                 if (delta > maxConnectTime_ms + 5000) {
    3768           0 :                     LOG(("Abandon half open to %s after %.2fms.\n",
    3769             :                          ent->mConnInfo->HashKey().get(), delta));
    3770             :                     half->Abandon();
    3771             :                 }
    3772           0 :             }
    3773           0 :         }
    3774           0 :         if (ent->mHalfOpens.Length()) {
    3775             :             mTimeoutTickNext = 1;
    3776           0 :         }
    3777             :     }
    3778             : 
    3779             :     if (mTimeoutTick) {
    3780             :         mTimeoutTickNext = std::max(mTimeoutTickNext, 1U);
    3781             :         mTimeoutTick->SetDelay(mTimeoutTickNext * 1000);
    3782             :     }
    3783             : }
    3784             : 
    3785           0 : // GetOrCreateConnectionEntry finds a ent for a particular CI for use in
    3786             : // dispatching a transaction according to these rules
    3787             : // 1] use an ent that matches the ci that can be dispatched immediately
    3788             : // 2] otherwise use an ent of wildcard(ci) than can be dispatched immediately
    3789           0 : // 3] otherwise create an ent that matches ci and make new conn on it
    3790           0 : 
    3791           0 : nsHttpConnectionMgr::nsConnectionEntry *
    3792             : nsHttpConnectionMgr::GetOrCreateConnectionEntry(nsHttpConnectionInfo *specificCI,
    3793             :                                                 bool prohibitWildCard)
    3794             : {
    3795             :     // step 1
    3796             :     nsConnectionEntry *specificEnt = mCT.GetWeak(specificCI->HashKey());
    3797           0 :     if (specificEnt && specificEnt->AvailableForDispatchNow()) {
    3798           0 :         return specificEnt;
    3799           0 :     }
    3800           0 : 
    3801           0 :     // step 1 repeated for an inverted anonymous flag; we return an entry
    3802           0 :     // only when it has an h2 established connection that is not authenticated
    3803           0 :     // with a client certificate.
    3804           0 :     RefPtr<nsHttpConnectionInfo> anonInvertedCI(specificCI->Clone());
    3805             :     anonInvertedCI->SetAnonymous(!specificCI->GetAnonymous());
    3806             :     nsConnectionEntry *invertedEnt = mCT.GetWeak(anonInvertedCI->HashKey());
    3807             :     if (invertedEnt) {
    3808             :         nsHttpConnection* h2conn = GetSpdyActiveConn(invertedEnt);
    3809           0 :         if (h2conn && h2conn->IsExperienced() && h2conn->NoClientCertAuth()) {
    3810           0 :             MOZ_ASSERT(h2conn->UsingSpdy());
    3811             :             LOG(("GetOrCreateConnectionEntry is coalescing h2 an/onymous connections, ent=%p", invertedEnt));
    3812             :             return invertedEnt;
    3813             :         }
    3814           0 :     }
    3815           0 : 
    3816           0 :     if (!specificCI->UsingHttpsProxy()) {
    3817           0 :         prohibitWildCard = true;
    3818           0 :     }
    3819           0 : 
    3820           0 :     // step 2
    3821             :     if (!prohibitWildCard) {
    3822             :         RefPtr<nsHttpConnectionInfo> wildCardProxyCI;
    3823             :         DebugOnly<nsresult> rv = specificCI->CreateWildCard(getter_AddRefs(wildCardProxyCI));
    3824             :         MOZ_ASSERT(NS_SUCCEEDED(rv));
    3825           0 :         nsConnectionEntry *wildCardEnt = mCT.GetWeak(wildCardProxyCI->HashKey());
    3826           0 :         if (wildCardEnt && wildCardEnt->AvailableForDispatchNow()) {
    3827           0 :             return wildCardEnt;
    3828           0 :         }
    3829             :     }
    3830           0 : 
    3831             :     // step 3
    3832             :     if (!specificEnt) {
    3833             :         RefPtr<nsHttpConnectionInfo> clone(specificCI->Clone());
    3834           0 :         specificEnt = new nsConnectionEntry(clone);
    3835             :         mCT.Put(clone->HashKey(), specificEnt);
    3836             :     }
    3837             :     return specificEnt;
    3838             : }
    3839           0 : 
    3840             : nsresult
    3841             : ConnectionHandle::OnHeadersAvailable(nsAHttpTransaction *trans,
    3842             :                                      nsHttpRequestHead *req,
    3843           0 :                                      nsHttpResponseHead *resp,
    3844             :                                      bool *reset)
    3845           0 : {
    3846           0 :     return mConn->OnHeadersAvailable(trans, req, resp, reset);
    3847             : }
    3848             : 
    3849           0 : void
    3850             : ConnectionHandle::CloseTransaction(nsAHttpTransaction *trans, nsresult reason)
    3851             : {
    3852             :     mConn->CloseTransaction(trans, reason);
    3853           0 : }
    3854             : 
    3855             : nsresult
    3856             : ConnectionHandle::TakeTransport(nsISocketTransport  **aTransport,
    3857           0 :                                 nsIAsyncInputStream **aInputStream,
    3858             :                                 nsIAsyncOutputStream **aOutputStream)
    3859           0 : {
    3860             :     return mConn->TakeTransport(aTransport, aInputStream, aOutputStream);
    3861           0 : }
    3862             : 
    3863           0 : void
    3864             : nsHttpConnectionMgr::OnMsgSpeculativeConnect(int32_t, ARefBase *param)
    3865             : {
    3866             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    3867           0 : 
    3868             :     SpeculativeConnectArgs *args = static_cast<SpeculativeConnectArgs *>(param);
    3869             : 
    3870           0 :     LOG(("nsHttpConnectionMgr::OnMsgSpeculativeConnect [ci=%s]\n",
    3871           0 :          args->mTrans->ConnectionInfo()->HashKey().get()));
    3872           0 : 
    3873           0 :     nsConnectionEntry *ent =
    3874             :         GetOrCreateConnectionEntry(args->mTrans->ConnectionInfo(), false);
    3875           0 : 
    3876           0 :     uint32_t parallelSpeculativeConnectLimit =
    3877           0 :         gHttpHandler->ParallelSpeculativeConnectLimit();
    3878           0 :     bool ignoreIdle = false;
    3879           0 :     bool isFromPredictor = false;
    3880             :     bool allow1918 = false;
    3881             : 
    3882           0 :     if (args->mOverridesOK) {
    3883           0 :         parallelSpeculativeConnectLimit = args->mParallelSpeculativeConnectLimit;
    3884           0 :         ignoreIdle = args->mIgnoreIdle;
    3885           0 :         isFromPredictor = args->mIsFromPredictor;
    3886           0 :         allow1918 = args->mAllow1918;
    3887           0 :     }
    3888           0 : 
    3889           0 :     bool keepAlive = args->mTrans->Caps() & NS_HTTP_ALLOW_KEEPALIVE;
    3890             :     if (mNumHalfOpenConns < parallelSpeculativeConnectLimit &&
    3891           0 :         ((ignoreIdle && (ent->mIdleConns.Length() < parallelSpeculativeConnectLimit)) ||
    3892           0 :          !ent->mIdleConns.Length()) &&
    3893             :         !(keepAlive && RestrictConnections(ent)) &&
    3894           0 :         !AtActiveConnectionLimit(ent, args->mTrans->Caps())) {
    3895             :         DebugOnly<nsresult> rv = CreateTransport(ent, args->mTrans,
    3896             :                                                  args->mTrans->Caps(), true,
    3897           0 :                                                  isFromPredictor, false,
    3898             :                                                  allow1918, nullptr);
    3899             :         MOZ_ASSERT(NS_SUCCEEDED(rv));
    3900           0 :     } else {
    3901             :         LOG(("OnMsgSpeculativeConnect Transport "
    3902           0 :              "not created due to existing connection count\n"));
    3903             :     }
    3904             : }
    3905             : 
    3906           0 : bool
    3907             : ConnectionHandle::IsPersistent()
    3908           0 : {
    3909             :     return mConn->IsPersistent();
    3910             : }
    3911             : 
    3912           0 : bool
    3913             : ConnectionHandle::IsReused()
    3914           0 : {
    3915           0 :     return mConn->IsReused();
    3916             : }
    3917             : 
    3918           0 : void
    3919             : ConnectionHandle::DontReuse()
    3920           0 : {
    3921             :     mConn->DontReuse();
    3922             : }
    3923             : 
    3924             : nsresult
    3925           0 : ConnectionHandle::PushBack(const char *buf, uint32_t bufLen)
    3926           0 : {
    3927             :     return mConn->PushBack(buf, bufLen);
    3928           0 : }
    3929           0 : 
    3930           0 : 
    3931           0 : //////////////////////// nsHalfOpenSocket
    3932           0 : NS_IMPL_ADDREF(nsHttpConnectionMgr::nsHalfOpenSocket)
    3933           0 : NS_IMPL_RELEASE(nsHttpConnectionMgr::nsHalfOpenSocket)
    3934           0 : 
    3935             : NS_INTERFACE_MAP_BEGIN(nsHttpConnectionMgr::nsHalfOpenSocket)
    3936           0 :     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
    3937           0 :     NS_INTERFACE_MAP_ENTRY(nsIOutputStreamCallback)
    3938           0 :     NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
    3939           0 :     NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
    3940             :     NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
    3941           0 :     NS_INTERFACE_MAP_ENTRY(nsINamed)
    3942             :     // we have no macro that covers this case.
    3943           0 :     if (aIID.Equals(NS_GET_IID(nsHttpConnectionMgr::nsHalfOpenSocket)) ) {
    3944             :         AddRef();
    3945             :         *aInstancePtr = this;
    3946             :         return NS_OK;
    3947             :     } else
    3948             : NS_INTERFACE_MAP_END
    3949           0 : 
    3950             : nsHttpConnectionMgr::
    3951             : nsHalfOpenSocket::nsHalfOpenSocket(nsConnectionEntry *ent,
    3952             :                                    nsAHttpTransaction *trans,
    3953             :                                    uint32_t caps,
    3954             :                                    bool speculative,
    3955             :                                    bool isFromPredictor,
    3956             :                                    bool urgentStart)
    3957             :     : mTransaction(trans)
    3958             :     , mDispatchedMTransaction(false)
    3959             :     , mCaps(caps)
    3960             :     , mSpeculative(speculative)
    3961             :     , mUrgentStart(urgentStart)
    3962             :     , mIsFromPredictor(isFromPredictor)
    3963             :     , mAllow1918(true)
    3964           0 :     , mHasConnected(false)
    3965             :     , mPrimaryConnectedOK(false)
    3966           0 :     , mBackupConnectedOK(false)
    3967           0 :     , mBackupConnStatsSet(false)
    3968             :     , mFreeToUse(true)
    3969             :     , mPrimaryStreamStatus(NS_OK)
    3970           0 :     , mFastOpenInProgress(false)
    3971           0 :     , mEnt(ent)
    3972           0 : {
    3973             :     MOZ_ASSERT(ent && trans, "constructor with null arguments");
    3974           0 :     LOG(("Creating nsHalfOpenSocket [this=%p trans=%p ent=%s key=%s]\n",
    3975           0 :          this, trans, ent->mConnInfo->Origin(), ent->mConnInfo->HashKey().get()));
    3976           0 : 
    3977             :     if (speculative) {
    3978             :         Telemetry::AutoCounter<Telemetry::HTTPCONNMGR_TOTAL_SPECULATIVE_CONN> totalSpeculativeConn;
    3979             :         ++totalSpeculativeConn;
    3980           0 : 
    3981           0 :         if (isFromPredictor) {
    3982             :           Telemetry::AutoCounter<Telemetry::PREDICTOR_TOTAL_PRECONNECTS_CREATED> totalPreconnectsCreated;
    3983           0 :           ++totalPreconnectsCreated;
    3984             :         }
    3985           0 :     }
    3986           0 : 
    3987             :     if (mEnt->mConnInfo->FirstHopSSL()) {
    3988           0 :       mFastOpenStatus = TFO_UNKNOWN;
    3989             :     } else {
    3990           0 :       mFastOpenStatus = TFO_HTTP;
    3991           0 :     }
    3992           0 :     MOZ_ASSERT(mEnt);
    3993             : }
    3994           0 : 
    3995           0 : nsHttpConnectionMgr::nsHalfOpenSocket::~nsHalfOpenSocket()
    3996           0 : {
    3997             :     MOZ_ASSERT(!mStreamOut);
    3998             :     MOZ_ASSERT(!mBackupStreamOut);
    3999           0 :     LOG(("Destroying nsHalfOpenSocket [this=%p]\n", this));
    4000             : 
    4001             :     if (mEnt)
    4002             :         mEnt->RemoveHalfOpen(this);
    4003             : }
    4004             : 
    4005           0 : nsresult
    4006             : nsHttpConnectionMgr::
    4007           0 : nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport,
    4008             :                                nsIAsyncInputStream **instream,
    4009             :                                nsIAsyncOutputStream **outstream,
    4010           0 :                                bool isBackup)
    4011           0 : {
    4012           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    4013           0 : 
    4014             :     MOZ_ASSERT(mEnt);
    4015           0 :     nsresult rv;
    4016           0 :     const char *socketTypes[1];
    4017           0 :     uint32_t typeCount = 0;
    4018             :     const nsHttpConnectionInfo *ci = mEnt->mConnInfo;
    4019             :     if (ci->FirstHopSSL()) {
    4020             :         socketTypes[typeCount++] = "ssl";
    4021           0 :     } else {
    4022           0 :         socketTypes[typeCount] = gHttpHandler->DefaultSocketType();
    4023             :         if (socketTypes[typeCount]) {
    4024           0 :             typeCount++;
    4025           0 :         }
    4026             :     }
    4027             : 
    4028             :     nsCOMPtr<nsISocketTransport> socketTransport;
    4029           0 :     nsCOMPtr<nsISocketTransportService> sts;
    4030             : 
    4031             :     sts = services::GetSocketTransportService();
    4032             :     if (!sts) {
    4033             :         return NS_ERROR_NOT_AVAILABLE;
    4034           0 :     }
    4035           0 : 
    4036           0 :     LOG(("nsHalfOpenSocket::SetupStreams [this=%p ent=%s] "
    4037             :          "setup routed transport to origin %s:%d via %s:%d\n",
    4038           0 :          this, ci->HashKey().get(),
    4039           0 :          ci->Origin(), ci->OriginPort(), ci->RoutedHost(), ci->RoutedPort()));
    4040             : 
    4041           0 :     nsCOMPtr<nsIRoutedSocketTransportService> routedSTS(do_QueryInterface(sts));
    4042             :     if (routedSTS) {
    4043             :         rv = routedSTS->CreateRoutedTransport(
    4044             :             socketTypes, typeCount,
    4045             :             ci->GetOrigin(), ci->OriginPort(), ci->GetRoutedHost(), ci->RoutedPort(),
    4046           0 :             ci->ProxyInfo(), getter_AddRefs(socketTransport));
    4047             :     } else {
    4048             :         if (!ci->GetRoutedHost().IsEmpty()) {
    4049             :             // There is a route requested, but the legacy nsISocketTransportService
    4050             :             // can't handle it.
    4051           0 :             // Origin should be reachable on origin host name, so this should
    4052           0 :             // not be a problem - but log it.
    4053           0 :             LOG(("nsHalfOpenSocket this=%p using legacy nsISocketTransportService "
    4054           0 :                  "means explicit route %s:%d will be ignored.\n", this,
    4055             :                  ci->RoutedHost(), ci->RoutedPort()));
    4056           0 :         }
    4057             : 
    4058           0 :         rv = sts->CreateTransport(socketTypes, typeCount,
    4059           0 :                                   ci->GetOrigin(), ci->OriginPort(),
    4060           0 :                                   ci->ProxyInfo(),
    4061             :                                   getter_AddRefs(socketTransport));
    4062           0 :     }
    4063           0 :     NS_ENSURE_SUCCESS(rv, rv);
    4064             : 
    4065           0 :     uint32_t tmpFlags = 0;
    4066           0 :     if (mCaps & NS_HTTP_REFRESH_DNS)
    4067             :         tmpFlags = nsISocketTransport::BYPASS_CACHE;
    4068           0 : 
    4069           0 :     if (mCaps & NS_HTTP_LOAD_ANONYMOUS)
    4070           0 :         tmpFlags |= nsISocketTransport::ANONYMOUS_CONNECT;
    4071             : 
    4072             :     if (ci->GetPrivate())
    4073           0 :         tmpFlags |= nsISocketTransport::NO_PERMANENT_STORAGE;
    4074           0 : 
    4075           0 :     if ((mCaps & NS_HTTP_BE_CONSERVATIVE) || ci->GetBeConservative()) {
    4076           0 :         LOG(("Setting Socket to BE_CONSERVATIVE"));
    4077           0 :         tmpFlags |= nsISocketTransport::BE_CONSERVATIVE;
    4078             :     }
    4079             : 
    4080             :     if (mEnt->PreferenceKnown()) {
    4081             :         if (mEnt->mPreferIPv6) {
    4082           0 :             tmpFlags |= nsISocketTransport::DISABLE_IPV4;
    4083             :         } else if (mEnt->mPreferIPv4) {
    4084             :             tmpFlags |= nsISocketTransport::DISABLE_IPV6;
    4085           0 :         }
    4086           0 : 
    4087           0 :         // In case the host is no longer accessible via the preferred IP family,
    4088           0 :         // try the opposite one and potentially restate the preference.
    4089             :         tmpFlags |= nsISocketTransport::RETRY_WITH_DIFFERENT_IP_FAMILY;
    4090           0 : 
    4091             :         // From the same reason, let the backup socket fail faster to try the other family.
    4092             :         uint16_t fallbackTimeout = isBackup ? gHttpHandler->GetFallbackSynTimeout() : 0;
    4093             :         if (fallbackTimeout) {
    4094             :             socketTransport->SetTimeout(nsISocketTransport::TIMEOUT_CONNECT,
    4095             :                                         fallbackTimeout);
    4096           1 :         }
    4097             :     } else if (isBackup && gHttpHandler->FastFallbackToIPv4()) {
    4098             :         // For backup connections, we disable IPv6. That's because some users have
    4099           0 :         // broken IPv6 connectivity (leading to very long timeouts), and disabling
    4100           0 :         // IPv6 on the backup connection gives them a much better user experience
    4101             :         // with dual-stack hosts, though they still pay the 250ms delay for each new
    4102             :         // connection. This strategy is also known as "happy eyeballs".
    4103           0 :         tmpFlags |= nsISocketTransport::DISABLE_IPV6;
    4104           0 :     }
    4105           0 : 
    4106             :     if (!Allow1918()) {
    4107           0 :         tmpFlags |= nsISocketTransport::DISABLE_RFC1918;
    4108             :     }
    4109             : 
    4110             :     if ((mFastOpenStatus != TFO_HTTP) && !isBackup) {
    4111           0 :         if (mEnt->mUseFastOpen) {
    4112           0 :             socketTransport->SetFastOpenCallback(this);
    4113             :         } else {
    4114           0 :             mFastOpenStatus = TFO_DISABLED;
    4115           0 :         }
    4116           0 :     }
    4117             : 
    4118             :     socketTransport->SetConnectionFlags(tmpFlags);
    4119           0 :     socketTransport->SetTlsFlags(ci->GetTlsFlags());
    4120             : 
    4121           0 :     const OriginAttributes& originAttributes = mEnt->mConnInfo->GetOriginAttributes();
    4122           0 :     if (originAttributes != OriginAttributes()) {
    4123             :         socketTransport->SetOriginAttributes(originAttributes);
    4124           0 :     }
    4125           0 : 
    4126             :     socketTransport->SetQoSBits(gHttpHandler->GetQoSBits());
    4127           0 : 
    4128           0 :     rv = socketTransport->SetEventSink(this, nullptr);
    4129           0 :     NS_ENSURE_SUCCESS(rv, rv);
    4130             : 
    4131           0 :     rv = socketTransport->SetSecurityCallbacks(this);
    4132           0 :     NS_ENSURE_SUCCESS(rv, rv);
    4133             : 
    4134           0 :     Telemetry::Accumulate(Telemetry::HTTP_CONNECTION_ENTRY_CACHE_HIT_1,
    4135           0 :                           mEnt->mUsedForConnection);
    4136             :     mEnt->mUsedForConnection = true;
    4137           0 : 
    4138           0 :     nsCOMPtr<nsIOutputStream> sout;
    4139             :     rv = socketTransport->OpenOutputStream(nsITransport::OPEN_UNBUFFERED,
    4140           0 :                                             0, 0,
    4141           0 :                                             getter_AddRefs(sout));
    4142             :     NS_ENSURE_SUCCESS(rv, rv);
    4143           0 : 
    4144           0 :     nsCOMPtr<nsIInputStream> sin;
    4145           0 :     rv = socketTransport->OpenInputStream(nsITransport::OPEN_UNBUFFERED,
    4146             :                                            0, 0,
    4147           0 :                                            getter_AddRefs(sin));
    4148           0 :     NS_ENSURE_SUCCESS(rv, rv);
    4149           0 : 
    4150             :     socketTransport.forget(transport);
    4151             :     CallQueryInterface(sin, instream);
    4152             :     CallQueryInterface(sout, outstream);
    4153             : 
    4154             :     rv = (*outstream)->AsyncWait(this, 0, 0, nullptr);
    4155           0 :     if (NS_SUCCEEDED(rv))
    4156             :         gHttpHandler->ConnMgr()->StartedConnect();
    4157           0 : 
    4158             :     return rv;
    4159             : }
    4160             : 
    4161           0 : nsresult
    4162           0 : nsHttpConnectionMgr::nsHalfOpenSocket::SetupPrimaryStreams()
    4163           0 : {
    4164           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    4165           0 : 
    4166             :     nsresult rv;
    4167           0 : 
    4168             :     mPrimarySynStarted = TimeStamp::Now();
    4169           0 :     rv = SetupStreams(getter_AddRefs(mSocketTransport),
    4170           0 :                       getter_AddRefs(mStreamIn),
    4171           0 :                       getter_AddRefs(mStreamOut),
    4172           0 :                       false);
    4173           0 : 
    4174             :     LOG(("nsHalfOpenSocket::SetupPrimaryStream [this=%p ent=%s rv=%" PRIx32 "]",
    4175           0 :          this, mEnt->mConnInfo->Origin(), static_cast<uint32_t>(rv)));
    4176           0 :     if (NS_FAILED(rv)) {
    4177           0 :         if (mStreamOut)
    4178             :             mStreamOut->AsyncWait(nullptr, 0, 0, nullptr);
    4179           0 :         if (mSocketTransport) {
    4180             :             mSocketTransport->SetFastOpenCallback(nullptr);
    4181             :         }
    4182             :         mStreamOut = nullptr;
    4183           1 :         mStreamIn = nullptr;
    4184             :         mSocketTransport = nullptr;
    4185           1 :     }
    4186             :     return rv;
    4187           1 : }
    4188           1 : 
    4189           1 : nsresult
    4190           1 : nsHttpConnectionMgr::nsHalfOpenSocket::SetupBackupStreams()
    4191           1 : {
    4192             :     MOZ_ASSERT(mTransaction);
    4193           1 : 
    4194             :     mBackupSynStarted = TimeStamp::Now();
    4195           1 :     nsresult rv = SetupStreams(getter_AddRefs(mBackupTransport),
    4196           0 :                                getter_AddRefs(mBackupStreamIn),
    4197           0 :                                getter_AddRefs(mBackupStreamOut),
    4198           0 :                                true);
    4199           0 : 
    4200           0 :     LOG(("nsHalfOpenSocket::SetupBackupStream [this=%p ent=%s rv=%" PRIx32 "]",
    4201             :          this, mEnt->mConnInfo->Origin(), static_cast<uint32_t>(rv)));
    4202           1 :     if (NS_FAILED(rv)) {
    4203             :         if (mBackupStreamOut)
    4204             :             mBackupStreamOut->AsyncWait(nullptr, 0, 0, nullptr);
    4205             :         mBackupStreamOut = nullptr;
    4206           0 :         mBackupStreamIn = nullptr;
    4207             :         mBackupTransport = nullptr;
    4208           0 :     }
    4209           0 :     return rv;
    4210           0 : }
    4211           0 : 
    4212           0 : void
    4213             : nsHttpConnectionMgr::nsHalfOpenSocket::SetupBackupTimer()
    4214             : {
    4215             :     MOZ_ASSERT(mEnt);
    4216           0 :     uint16_t timeout = gHttpHandler->GetIdleSynTimeout();
    4217           0 :     MOZ_ASSERT(!mSynTimer, "timer already initd");
    4218             :     if (!timeout && mFastOpenInProgress) {
    4219             :         timeout = 250;
    4220             :     }
    4221             :     // When using Fast Open the correct transport will be setup for sure (it is
    4222             :     // guaranteed), but it can be that it will happened a bit later.
    4223             :     if (mFastOpenInProgress ||
    4224             :         (timeout && !mSpeculative)) {
    4225           0 :         // Setup the timer that will establish a backup socket
    4226           0 :         // if we do not get a writable event on the main one.
    4227           0 :         // We do this because a lost SYN takes a very long time
    4228           0 :         // to repair at the TCP level.
    4229           0 :         //
    4230             :         // Failure to setup the timer is something we can live with,
    4231           0 :         // so don't return an error in that case.
    4232             :         NS_NewTimerWithCallback(getter_AddRefs(mSynTimer),
    4233             :                                 this, timeout, nsITimer::TYPE_ONE_SHOT);
    4234           0 :         LOG(("nsHalfOpenSocket::SetupBackupTimer() [this=%p]", this));
    4235             :     } else if (timeout) {
    4236             :         LOG(("nsHalfOpenSocket::SetupBackupTimer() [this=%p], did not arm\n", this));
    4237             :     }
    4238           0 : }
    4239             : 
    4240             : void
    4241           0 : nsHttpConnectionMgr::nsHalfOpenSocket::CancelBackupTimer()
    4242           0 : {
    4243             :     // If the syntimer is still armed, we can cancel it because no backup
    4244             :     // socket should be formed at this point
    4245             :     if (!mSynTimer)
    4246             :         return;
    4247             : 
    4248             :     LOG(("nsHalfOpenSocket::CancelBackupTimer()"));
    4249           0 :     mSynTimer->Cancel();
    4250             : 
    4251           0 :     // Keeping the reference to the timer to remember we have already
    4252             :     // performed the backup connection.
    4253             : }
    4254             : 
    4255             : void
    4256           0 : nsHttpConnectionMgr::nsHalfOpenSocket::Abandon()
    4257             : {
    4258           0 :     LOG(("nsHalfOpenSocket::Abandon [this=%p ent=%s] %p %p %p %p",
    4259             :          this, mEnt->mConnInfo->Origin(),
    4260             :          mSocketTransport.get(), mBackupTransport.get(),
    4261           0 :          mStreamOut.get(), mBackupStreamOut.get()));
    4262           0 : 
    4263           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    4264           0 : 
    4265           0 :     RefPtr<nsHalfOpenSocket> deleteProtector(this);
    4266             : 
    4267           0 :     // Tell socket (and backup socket) to forget the half open socket.
    4268           0 :     if (mSocketTransport) {
    4269           0 :         mSocketTransport->SetEventSink(nullptr, nullptr);
    4270           0 :         mSocketTransport->SetSecurityCallbacks(nullptr);
    4271             :         mSocketTransport->SetFastOpenCallback(nullptr);
    4272             :         mSocketTransport = nullptr;
    4273             :     }
    4274           0 :     if (mBackupTransport) {
    4275           0 :         mBackupTransport->SetEventSink(nullptr, nullptr);
    4276             :         mBackupTransport->SetSecurityCallbacks(nullptr);
    4277             :         mBackupTransport = nullptr;
    4278           0 :     }
    4279             : 
    4280           0 :     // Tell output stream (and backup) to forget the half open socket.
    4281           0 :     if (mStreamOut) {
    4282             :         if (!mFastOpenInProgress) {
    4283           0 :             // If mFastOpenInProgress is true HalfOpen are not in mHalfOpen
    4284           0 :             // list and are not counted so we do not need to decrease counter.
    4285           0 :             gHttpHandler->ConnMgr()->RecvdConnect();
    4286           0 :         }
    4287             :         mStreamOut->AsyncWait(nullptr, 0, 0, nullptr);
    4288             :         mStreamOut = nullptr;
    4289             :     }
    4290           0 :     if (mBackupStreamOut) {
    4291           0 :         gHttpHandler->ConnMgr()->RecvdConnect();
    4292           0 :         mBackupStreamOut->AsyncWait(nullptr, 0, 0, nullptr);
    4293             :         mBackupStreamOut = nullptr;
    4294           0 :     }
    4295           0 : 
    4296           0 :     // Lose references to input stream (and backup).
    4297             :     if (mStreamIn) {
    4298             :         mStreamIn->AsyncWait(nullptr, 0, 0, nullptr);
    4299             :         mStreamIn = nullptr;
    4300           0 :     }
    4301             :     if (mBackupStreamIn) {
    4302             :         mBackupStreamIn->AsyncWait(nullptr, 0, 0, nullptr);
    4303           0 :         mBackupStreamIn = nullptr;
    4304           0 :     }
    4305           0 : 
    4306             :     // Stop the timer - we don't want any new backups.
    4307           0 :     CancelBackupTimer();
    4308           0 : 
    4309             :     // Remove the half open from the connection entry.
    4310             :     if (mEnt) {
    4311           0 :         mEnt->mDoNotDestroy = false;
    4312             :         mEnt->RemoveHalfOpen(this);
    4313           0 :     }
    4314             :     mEnt = nullptr;
    4315             : }
    4316           0 : 
    4317             : double
    4318             : nsHttpConnectionMgr::nsHalfOpenSocket::Duration(TimeStamp epoch)
    4319             : {
    4320             :     if (mPrimarySynStarted.IsNull())
    4321           1 :         return 0;
    4322             : 
    4323           1 :     return (epoch - mPrimarySynStarted).ToMilliseconds();
    4324           1 : }
    4325             : 
    4326           1 : 
    4327           1 : NS_IMETHODIMP // method for nsITimerCallback
    4328           1 : nsHttpConnectionMgr::nsHalfOpenSocket::Notify(nsITimer *timer)
    4329             : {
    4330           1 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    4331           1 :     MOZ_ASSERT(timer == mSynTimer, "wrong timer");
    4332             : 
    4333             :     MOZ_ASSERT(!mBackupTransport);
    4334             :     MOZ_ASSERT(mSynTimer);
    4335             :     MOZ_ASSERT(mEnt);
    4336           1 : 
    4337             :     DebugOnly<nsresult> rv = SetupBackupStreams();
    4338             :     MOZ_ASSERT(NS_SUCCEEDED(rv));
    4339             : 
    4340           0 :     // Keeping the reference to the timer to remember we have already
    4341             :     // performed the backup connection.
    4342           0 : 
    4343           0 :     return NS_OK;
    4344             : }
    4345             : 
    4346             : NS_IMETHODIMP // method for nsINamed
    4347           0 : nsHttpConnectionMgr::nsHalfOpenSocket::GetName(nsACString& aName)
    4348             : {
    4349             :   aName.AssignLiteral("nsHttpConnectionMgr::nsHalfOpenSocket");
    4350             :   return NS_OK;
    4351           0 : }
    4352             : 
    4353             : already_AddRefed<nsHttpConnectionMgr::PendingTransactionInfo>
    4354           0 : nsHttpConnectionMgr::
    4355           0 : nsHalfOpenSocket::FindTransactionHelper(bool removeWhenFound)
    4356             : {
    4357           0 :     nsTArray<RefPtr<PendingTransactionInfo>> *pendingQ =
    4358           0 :         gHttpHandler->ConnMgr()->GetTransactionPendingQHelper(mEnt, mTransaction);
    4359           0 : 
    4360           0 :     int32_t index = pendingQ
    4361           0 :         ? pendingQ->IndexOf(mTransaction, 0, PendingComparator())
    4362             :         : -1;
    4363             : 
    4364           0 :     RefPtr<PendingTransactionInfo> info;
    4365             :     if (index != -1) {
    4366             :         info = (*pendingQ)[index];
    4367             :         if (removeWhenFound) {
    4368             :             pendingQ->RemoveElementAt(index);
    4369           0 :         }
    4370             :     }
    4371             :     return info.forget();
    4372           0 : }
    4373           0 : 
    4374           0 : // method for nsIAsyncOutputStreamCallback
    4375             : NS_IMETHODIMP
    4376           0 : nsHttpConnectionMgr::
    4377             : nsHalfOpenSocket::OnOutputStreamReady(nsIAsyncOutputStream *out)
    4378           0 : {
    4379             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    4380             :     MOZ_ASSERT(mStreamOut || mBackupStreamOut);
    4381             :     MOZ_ASSERT(out == mStreamOut || out == mBackupStreamOut,
    4382           0 :                           "stream mismatch");
    4383           0 :     MOZ_ASSERT(mEnt);
    4384             : 
    4385           0 :     LOG(("nsHalfOpenSocket::OnOutputStreamReady [this=%p ent=%s %s]\n",
    4386             :          this, mEnt->mConnInfo->Origin(),
    4387           0 :          out == mStreamOut ? "primary" : "backup"));
    4388           0 : 
    4389             :     mEnt->mDoNotDestroy = true;
    4390             :     gHttpHandler->ConnMgr()->RecvdConnect();
    4391             : 
    4392             :     CancelBackupTimer();
    4393             : 
    4394             :     if (mFastOpenInProgress) {
    4395           0 :         LOG(("nsHalfOpenSocket::OnOutputStreamReady backup stream is ready, "
    4396             :              "close the fast open socket %p [this=%p ent=%s]\n",
    4397             :              mSocketTransport.get(), this, mEnt->mConnInfo->Origin()));
    4398             :         // If fast open is used, right after a socket for the primary stream is
    4399             :         // created a nsHttpConnection is created for that socket. The connection
    4400             :         // listens for  OnOutputStreamReady not HalfOpenSocket. So this stream
    4401             :         // cannot be mStreamOut.
    4402             :         MOZ_ASSERT((out == mBackupStreamOut) && mConnectionNegotiatingFastOpen);
    4403             :         // Here the backup, non-TFO connection has connected successfully,
    4404             :         // before the TFO connection.
    4405           0 :         //
    4406           0 :         // The primary, TFO connection will be cancelled and the transaction
    4407           0 :         // will be rewind. CloseConnectionFastOpenTakesTooLongOrError will
    4408             :         // return the rewind transaction. The transaction will be put back to
    4409           0 :         // the pending queue and as well connected to this halfOpenSocket.
    4410           0 :         // SetupConn should set up a new nsHttpConnection with the backup
    4411           0 :         // socketTransport and the rewind transaction.
    4412           0 :         mSocketTransport->SetFastOpenCallback(nullptr);
    4413             :         mConnectionNegotiatingFastOpen->SetFastOpen(false);
    4414           0 :         mEnt->mHalfOpenFastOpenBackups.RemoveElement(this);
    4415             :         RefPtr<nsAHttpTransaction> trans =
    4416           0 :             mConnectionNegotiatingFastOpen->CloseConnectionFastOpenTakesTooLongOrError(true);
    4417           0 :         mSocketTransport = nullptr;
    4418           0 :         mStreamOut = nullptr;
    4419           0 :         mStreamIn = nullptr;
    4420           0 : 
    4421             :         if (trans && trans->QueryHttpTransaction()) {
    4422           0 :             RefPtr<PendingTransactionInfo> pendingTransInfo =
    4423             :                 new PendingTransactionInfo(trans->QueryHttpTransaction());
    4424           0 :             pendingTransInfo->mHalfOpen =
    4425             :                 do_GetWeakReference(static_cast<nsISupportsWeakReference*>(this));
    4426             :             if (trans->Caps() & NS_HTTP_URGENT_START) {
    4427           0 :                 gHttpHandler->ConnMgr()->InsertTransactionSorted(mEnt->mUrgentStartQ,
    4428           0 :                                                                  pendingTransInfo,
    4429           0 :                                                                  true);
    4430             :             } else {
    4431             :                 mEnt->InsertTransaction(pendingTransInfo, true);
    4432           0 :             }
    4433           0 :         }
    4434           0 :         if (mEnt->mUseFastOpen) {
    4435           0 :             gHttpHandler->IncrementFastOpenConsecutiveFailureCounter();
    4436           0 :             mEnt->mUseFastOpen = false;
    4437           0 :         }
    4438           0 : 
    4439           0 :         mFastOpenInProgress = false;
    4440             :         mConnectionNegotiatingFastOpen = nullptr;
    4441             :         if (mFastOpenStatus == TFO_NOT_TRIED) {
    4442             :             mFastOpenStatus = TFO_FAILED_BACKUP_CONNECTION_TFO_NOT_TRIED;
    4443             :         } else if (mFastOpenStatus == TFO_TRIED) {
    4444           0 :             mFastOpenStatus = TFO_FAILED_BACKUP_CONNECTION_TFO_TRIED;
    4445             :         } else if (mFastOpenStatus == TFO_DATA_SENT) {
    4446             :             mFastOpenStatus = TFO_FAILED_BACKUP_CONNECTION_TFO_DATA_SENT;
    4447             :         } else {
    4448           0 :             // This is TFO_DATA_COOKIE_NOT_ACCEPTED (I think this cannot
    4449           0 :             // happened, because the primary connection will be already
    4450             :             // connected or in recovery and mFastOpenInProgress==false).
    4451             :             mFastOpenStatus = TFO_FAILED_BACKUP_CONNECTION_TFO_DATA_COOKIE_NOT_ACCEPTED;
    4452             :         }
    4453           0 :     }
    4454           0 : 
    4455           0 :     if (((mFastOpenStatus == TFO_DISABLED) ||
    4456             :         (mFastOpenStatus == TFO_HTTP)) && !mBackupConnStatsSet) {
    4457             :         // Collect telemetry for backup connection being faster than primary
    4458           0 :         // connection. We want to collect this telemetry only for cases where
    4459           0 :         // TFO is not used.
    4460           0 :         mBackupConnStatsSet = true;
    4461           0 :         Telemetry::Accumulate(Telemetry::NETWORK_HTTP_BACKUP_CONN_WON_1,
    4462           0 :                               (out == mBackupStreamOut));
    4463           0 :     }
    4464           0 : 
    4465           0 :     if (mFastOpenStatus == TFO_UNKNOWN) {
    4466           0 :         MOZ_ASSERT(out == mStreamOut);
    4467           0 :         if (mPrimaryStreamStatus == NS_NET_STATUS_RESOLVING_HOST) {
    4468             :             mFastOpenStatus = TFO_UNKNOWN_RESOLVING;
    4469             :         } else if (mPrimaryStreamStatus == NS_NET_STATUS_RESOLVED_HOST) {
    4470           0 :             mFastOpenStatus = TFO_UNKNOWN_RESOLVED;
    4471           0 :         } else if (mPrimaryStreamStatus == NS_NET_STATUS_CONNECTING_TO) {
    4472           0 :             mFastOpenStatus = TFO_UNKNOWN_CONNECTING;
    4473             :         } else if (mPrimaryStreamStatus == NS_NET_STATUS_CONNECTED_TO) {
    4474           0 :             mFastOpenStatus = TFO_UNKNOWN_CONNECTED;
    4475             :         }
    4476             :     }
    4477             :     nsresult rv = SetupConn(out, false);
    4478           0 :     if (mEnt) {
    4479             :         mEnt->mDoNotDestroy = false;
    4480             :     }
    4481           0 :     return rv;
    4482             : }
    4483           0 : 
    4484             : bool
    4485           0 : nsHttpConnectionMgr::
    4486             : nsHalfOpenSocket::FastOpenEnabled()
    4487             : {
    4488             :     LOG(("nsHalfOpenSocket::FastOpenEnabled [this=%p]\n", this));
    4489           0 : 
    4490             :     MOZ_ASSERT(mEnt);
    4491             : 
    4492             :     if (!mEnt) {
    4493           0 :         return false;
    4494             :     }
    4495             : 
    4496             :     MOZ_ASSERT(mEnt->mConnInfo->FirstHopSSL());
    4497           0 : 
    4498             :     // If mEnt is present this HalfOpen must be in the mHalfOpens,
    4499           0 :     // but we want to be sure!!!
    4500           0 :     if (!mEnt->mHalfOpens.Contains(this)) {
    4501           0 :         return false;
    4502           0 :     }
    4503             : 
    4504             :     if (!gHttpHandler->UseFastOpen()) {
    4505             :         // fast open was turned off.
    4506             :         LOG(("nsHalfOpenSocket::FastEnabled - fast open was turned off.\n"));
    4507             :         mEnt->mUseFastOpen = false;
    4508             :         mFastOpenStatus = TFO_DISABLED;
    4509             :         return false;
    4510           0 :     }
    4511           0 :     // We can use FastOpen if we have a transaction or if it is ssl
    4512           0 :     // connection. For ssl we will use a null transaction to drive the SSL
    4513           0 :     // handshake to completion if there is not a pending transaction. Afterwards
    4514             :     // the connection will be 100% ready for the next transaction to use it.
    4515             :     // Make an exception for SSL tunneled HTTP proxy as the NullHttpTransaction
    4516             :     // does not know how to drive Connect.
    4517             :     if (mEnt->mConnInfo->UsingConnect()) {
    4518             :         LOG(("nsHalfOpenSocket::FastOpenEnabled - It is using Connect."));
    4519           0 :         mFastOpenStatus = TFO_DISABLED_CONNECT;
    4520             :         return false;
    4521             :     }
    4522           0 :     return true;
    4523           0 : }
    4524           0 : 
    4525           0 : nsresult
    4526             : nsHttpConnectionMgr::
    4527           0 : nsHalfOpenSocket::StartFastOpen()
    4528             : {
    4529             :     MOZ_ASSERT(mStreamOut);
    4530           0 :     MOZ_ASSERT(!mBackupTransport);
    4531             :     MOZ_ASSERT(mEnt);
    4532           0 :     MOZ_ASSERT(mFastOpenStatus == TFO_UNKNOWN);
    4533           0 : 
    4534             :     LOG(("nsHalfOpenSocket::StartFastOpen [this=%p]\n",
    4535             :          this));
    4536           0 : 
    4537           0 :     RefPtr<nsHalfOpenSocket> deleteProtector(this);
    4538             : 
    4539             :     mFastOpenInProgress = true;
    4540             :     mEnt->mDoNotDestroy = true;
    4541             :     // Remove this HalfOpen from mEnt->mHalfOpens.
    4542             :     // The new connection will take care of closing this HalfOpen from now on!
    4543             :     if (!mEnt->mHalfOpens.RemoveElement(this)) {
    4544             :         MOZ_ASSERT(false, "HalfOpen is not in mHalfOpens!");
    4545             :         mSocketTransport->SetFastOpenCallback(nullptr);
    4546           0 :         CancelBackupTimer();
    4547           0 :         mFastOpenInProgress = false;
    4548           0 :         Abandon();
    4549             :         mFastOpenStatus = TFO_INIT_FAILED;
    4550             :         return NS_ERROR_ABORT;
    4551             :     }
    4552           0 : 
    4553             :     MOZ_ASSERT(gHttpHandler->ConnMgr()->mNumHalfOpenConns);
    4554             :     if (gHttpHandler->ConnMgr()->mNumHalfOpenConns) { // just in case
    4555           0 :         gHttpHandler->ConnMgr()->mNumHalfOpenConns--;
    4556           0 :     }
    4557           0 : 
    4558             :     // Count this socketTransport as connected.
    4559           0 :     gHttpHandler->ConnMgr()->RecvdConnect();
    4560           0 : 
    4561           0 :     // Remove HalfOpen from callbacks, the new connection will take them.
    4562             :     mSocketTransport->SetEventSink(nullptr, nullptr);
    4563           0 :     mSocketTransport->SetSecurityCallbacks(nullptr);
    4564           0 :     mStreamOut->AsyncWait(nullptr, 0, 0, nullptr);
    4565             : 
    4566             :     nsresult rv = SetupConn(mStreamOut, true);
    4567             :     if (!mConnectionNegotiatingFastOpen) {
    4568             :         LOG(("nsHalfOpenSocket::StartFastOpen SetupConn failed "
    4569           0 :              "[this=%p rv=%x]\n", this, static_cast<uint32_t>(rv)));
    4570           0 :         if (NS_SUCCEEDED(rv)) {
    4571           0 :             rv = NS_ERROR_ABORT;
    4572             :         }
    4573             :         // If SetupConn failed this will CloseTransaction and socketTransport
    4574             :         // with an error, therefore we can close this HalfOpen. socketTransport
    4575           0 :         // will remove reference to this HalfOpen as well.
    4576           0 :         mSocketTransport->SetFastOpenCallback(nullptr);
    4577             :         CancelBackupTimer();
    4578           0 :         mFastOpenInProgress = false;
    4579             : 
    4580             :         // The connection is responsible to take care of the halfOpen so we
    4581           0 :         // need to clean it up.
    4582             :         Abandon();
    4583             :         mFastOpenStatus = TFO_INIT_FAILED;
    4584             :     } else {
    4585           0 :         LOG(("nsHalfOpenSocket::StartFastOpen [this=%p conn=%p]\n",
    4586             :              this, mConnectionNegotiatingFastOpen.get()));
    4587             : 
    4588             :         mEnt->mHalfOpenFastOpenBackups.AppendElement(this);
    4589           0 :         // SetupBackupTimer should setup timer which will hold a ref to this
    4590             :         // halfOpen. It will failed only if it cannot create timer. Anyway just
    4591             :         // to be sure I will add this deleteProtector!!!
    4592           0 :         if (!mSynTimer) {
    4593           0 :             // For Fast Open we will setup backup timer also for
    4594             :             // NullTransaction.
    4595             :             // So maybe it is not set and we need to set it here.
    4596             :             SetupBackupTimer();
    4597             :         }
    4598             :     }
    4599           0 :     if (mEnt) {
    4600             :       mEnt->mDoNotDestroy = false;
    4601             :     }
    4602           0 :     return rv;
    4603           0 : }
    4604             : 
    4605           0 : void
    4606             : nsHttpConnectionMgr::
    4607             : nsHalfOpenSocket::SetFastOpenConnected(nsresult aError, bool aWillRetry)
    4608             : {
    4609             :     MOZ_ASSERT(mFastOpenInProgress);
    4610             :     MOZ_ASSERT(mEnt);
    4611             : 
    4612             :     LOG(("nsHalfOpenSocket::SetFastOpenConnected [this=%p conn=%p error=%x]\n",
    4613             :          this, mConnectionNegotiatingFastOpen.get(),
    4614             :          static_cast<uint32_t>(aError)));
    4615             : 
    4616             :     // mConnectionNegotiatingFastOpen is set after a StartFastOpen creates
    4617             :     // and activates a nsHttpConnection successfully (SetupConn calls
    4618             :     // DispatchTransaction and DispatchAbstractTransaction which calls
    4619           0 :     // conn->Activate).
    4620           0 :     // nsHttpConnection::Activate can fail which will close socketTransport
    4621             :     // and socketTransport will call this function. The FastOpen clean up
    4622             :     // in case nsHttpConnection::Activate fails will be done in StartFastOpen.
    4623           0 :     // Also OnMsgReclaimConnection can decided that we do not need this
    4624             :     // transaction and cancel it as well.
    4625             :     // In all other cases mConnectionNegotiatingFastOpen must not be nullptr.
    4626             :     if (!mConnectionNegotiatingFastOpen) {
    4627             :         return;
    4628             :     }
    4629           0 : 
    4630             :     MOZ_ASSERT((mFastOpenStatus == TFO_NOT_TRIED) ||
    4631           0 :                (mFastOpenStatus == TFO_DATA_SENT) ||
    4632             :                (mFastOpenStatus == TFO_TRIED) ||
    4633             :                (mFastOpenStatus == TFO_DATA_COOKIE_NOT_ACCEPTED) ||
    4634           0 :                (mFastOpenStatus == TFO_DISABLED));
    4635           0 : 
    4636             :     RefPtr<nsHalfOpenSocket> deleteProtector(this);
    4637           0 : 
    4638             :     mEnt->mDoNotDestroy = true;
    4639             : 
    4640           0 :     // Delete 2 points of entry to FastOpen function so that we do not reenter.
    4641           0 :     mEnt->mHalfOpenFastOpenBackups.RemoveElement(this);
    4642             :     mSocketTransport->SetFastOpenCallback(nullptr);
    4643             : 
    4644             :     mConnectionNegotiatingFastOpen->SetFastOpen(false);
    4645             : 
    4646             :     // Check if we want to restart connection!
    4647             :     if (aWillRetry &&
    4648           0 :         ((aError == NS_ERROR_CONNECTION_REFUSED) ||
    4649             : #if defined(_WIN64) && defined(WIN95)
    4650           0 :          // On Windows PR_ContinueConnect can return NS_ERROR_FAILURE.
    4651           0 :          // This will be fixed in bug 1386719 and this is just a temporary
    4652           0 :          // work around.
    4653             :          (aError == NS_ERROR_FAILURE) ||
    4654             : #endif
    4655             :          (aError == NS_ERROR_PROXY_CONNECTION_REFUSED) ||
    4656             :          (aError == NS_ERROR_NET_TIMEOUT))) {
    4657             :         if (mEnt->mUseFastOpen) {
    4658           0 :             gHttpHandler->IncrementFastOpenConsecutiveFailureCounter();
    4659           0 :             mEnt->mUseFastOpen = false;
    4660             :         }
    4661           0 :         // This is called from nsSocketTransport::RecoverFromError. The
    4662           0 :         // socket will try connect and we need to rewind nsHttpTransaction.
    4663           0 : 
    4664           0 :         RefPtr<nsAHttpTransaction> trans =
    4665           0 :             mConnectionNegotiatingFastOpen->CloseConnectionFastOpenTakesTooLongOrError(false);
    4666             :         if (trans && trans->QueryHttpTransaction()) {
    4667           0 :             RefPtr<PendingTransactionInfo> pendingTransInfo =
    4668             :                 new PendingTransactionInfo(trans->QueryHttpTransaction());
    4669           0 :             pendingTransInfo->mHalfOpen =
    4670             :                 do_GetWeakReference(static_cast<nsISupportsWeakReference*>(this));
    4671             :             if (trans->Caps() & NS_HTTP_URGENT_START) {
    4672             :                 gHttpHandler->ConnMgr()->InsertTransactionSorted(mEnt->mUrgentStartQ,
    4673             :                                                                  pendingTransInfo,
    4674             :                                                                  true);
    4675             :             } else {
    4676             :                 mEnt->InsertTransaction(pendingTransInfo, true);
    4677             :             }
    4678           0 :         }
    4679           0 :         // We are doing a restart without fast open, so the easiest way is to
    4680           0 :         // return mSocketTransport to the halfOpenSock and destroy connection.
    4681             :         // This makes http2 implemenntation easier.
    4682             :         // mConnectionNegotiatingFastOpen is going away and halfOpen is taking
    4683           0 :         // this mSocketTransport so add halfOpen to mEnt and update
    4684           0 :         // mNumActiveConns.
    4685           0 :         mEnt->mHalfOpens.AppendElement(this);
    4686           0 :         gHttpHandler->ConnMgr()->mNumHalfOpenConns++;
    4687             :         gHttpHandler->ConnMgr()->StartedConnect();
    4688           0 : 
    4689             :         // Restore callbacks.
    4690           0 :         mStreamOut->AsyncWait(this, 0, 0, nullptr);
    4691           0 :         mSocketTransport->SetEventSink(this, nullptr);
    4692           0 :         mSocketTransport->SetSecurityCallbacks(this);
    4693             :         mStreamIn->AsyncWait(nullptr, 0, 0, nullptr);
    4694           0 : 
    4695           0 :         if ((aError == NS_ERROR_CONNECTION_REFUSED) ||
    4696             :             (aError == NS_ERROR_PROXY_CONNECTION_REFUSED)) {
    4697             :             mFastOpenStatus = TFO_FAILED_CONNECTION_REFUSED;
    4698             :         } else if (aError == NS_ERROR_NET_TIMEOUT) {
    4699             :             mFastOpenStatus = TFO_FAILED_NET_TIMEOUT;
    4700           0 :         } else {
    4701           0 :             mFastOpenStatus = TFO_FAILED_UNKNOW_ERROR;
    4702             :         }
    4703           0 : 
    4704           0 :     } else {
    4705             :         // On success or other error we proceed with connection, we just need
    4706           0 :         // to close backup timer and halfOpenSock.
    4707             :         CancelBackupTimer();
    4708           0 :         if (NS_SUCCEEDED(aError)) {
    4709           0 :             NetAddr peeraddr;
    4710           0 :             if (NS_SUCCEEDED(mSocketTransport->GetPeerAddr(&peeraddr))) {
    4711             :                 mEnt->RecordIPFamilyPreference(peeraddr.raw.family);
    4712             :             }
    4713             :             gHttpHandler->ResetFastOpenConsecutiveFailureCounter();
    4714           0 :         }
    4715           0 :         mSocketTransport = nullptr;
    4716           0 :         mStreamOut = nullptr;
    4717           0 :         mStreamIn = nullptr;
    4718             : 
    4719             :         // If backup transport has already started put this HalfOpen back to
    4720             :         // mEnt list.
    4721           0 :         if (mBackupTransport) {
    4722           0 :             mFastOpenStatus = TFO_BACKUP_CONN;
    4723           0 :             mEnt->mHalfOpens.AppendElement(this);
    4724           0 :             gHttpHandler->ConnMgr()->mNumHalfOpenConns++;
    4725             :         }
    4726           0 :     }
    4727           0 : 
    4728             :     mFastOpenInProgress = false;
    4729             :     mConnectionNegotiatingFastOpen = nullptr;
    4730             :     if (mEnt) {
    4731             :         mEnt->mDoNotDestroy = false;
    4732           0 :     } else {
    4733             :         MOZ_ASSERT(!mBackupTransport);
    4734             :         MOZ_ASSERT(!mBackupStreamOut);
    4735           0 :     }
    4736           0 : }
    4737             : 
    4738           0 : void
    4739           0 : nsHttpConnectionMgr::
    4740           0 : nsHalfOpenSocket::SetFastOpenStatus(uint8_t tfoStatus)
    4741             : {
    4742           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    4743             :     MOZ_ASSERT(mFastOpenInProgress);
    4744           0 : 
    4745             :     mFastOpenStatus = tfoStatus;
    4746             :     mConnectionNegotiatingFastOpen->SetFastOpenStatus(tfoStatus);
    4747           0 :     if (mConnectionNegotiatingFastOpen->Transaction()) {
    4748             :         // The transaction could already be canceled in the meantime, hence nullified.
    4749             :         mConnectionNegotiatingFastOpen->Transaction()->SetFastOpenStatus(tfoStatus);
    4750           0 :     }
    4751             : }
    4752           0 : 
    4753             : void
    4754             : nsHttpConnectionMgr::
    4755           0 : nsHalfOpenSocket::CancelFastOpenConnection()
    4756           0 : {
    4757           0 :     MOZ_ASSERT(mFastOpenInProgress);
    4758           0 : 
    4759             :     LOG(("nsHalfOpenSocket::CancelFastOpenConnection [this=%p conn=%p]\n",
    4760           0 :          this, mConnectionNegotiatingFastOpen.get()));
    4761           0 : 
    4762           0 :     RefPtr<nsHalfOpenSocket> deleteProtector(this);
    4763           0 :     mEnt->mHalfOpenFastOpenBackups.RemoveElement(this);
    4764             :     mSocketTransport->SetFastOpenCallback(nullptr);
    4765           0 :     mConnectionNegotiatingFastOpen->SetFastOpen(false);
    4766             :     RefPtr<nsAHttpTransaction> trans =
    4767           0 :         mConnectionNegotiatingFastOpen->CloseConnectionFastOpenTakesTooLongOrError(true);
    4768             :     mSocketTransport = nullptr;
    4769           0 :     mStreamOut = nullptr;
    4770           0 :     mStreamIn = nullptr;
    4771           0 : 
    4772             :     if (trans && trans->QueryHttpTransaction()) {
    4773           0 :         RefPtr<PendingTransactionInfo> pendingTransInfo =
    4774             :             new PendingTransactionInfo(trans->QueryHttpTransaction());
    4775             : 
    4776             :         if (trans->Caps() & NS_HTTP_URGENT_START) {
    4777           0 :             gHttpHandler->ConnMgr()->InsertTransactionSorted(mEnt->mUrgentStartQ,
    4778           0 :                                                              pendingTransInfo, true);
    4779           0 :         } else {
    4780             :             mEnt->InsertTransaction(pendingTransInfo, true);
    4781           0 :         }
    4782           0 :     }
    4783           0 : 
    4784             :     mFastOpenInProgress = false;
    4785             :     mConnectionNegotiatingFastOpen = nullptr;
    4786           0 :     Abandon();
    4787             : 
    4788             :     MOZ_ASSERT(!mBackupTransport);
    4789           0 :     MOZ_ASSERT(!mBackupStreamOut);
    4790           0 : }
    4791           0 : 
    4792             : void
    4793             : nsHttpConnectionMgr::
    4794           0 : nsHalfOpenSocket::FastOpenNotSupported()
    4795             : {
    4796             :   MOZ_ASSERT(mFastOpenInProgress);
    4797             :   gHttpHandler->SetFastOpenNotSupported();
    4798           0 : }
    4799             : 
    4800           0 : nsresult
    4801           0 : nsHttpConnectionMgr::
    4802             : nsHalfOpenSocket::SetupConn(nsIAsyncOutputStream *out,
    4803             :                             bool aFastOpen)
    4804           0 : {
    4805           0 :     MOZ_ASSERT(!aFastOpen || (out == mStreamOut));
    4806           0 :     // assign the new socket to the http connection
    4807             :     RefPtr<nsHttpConnection> conn = new nsHttpConnection();
    4808             :     LOG(("nsHalfOpenSocket::SetupConn "
    4809             :          "Created new nshttpconnection %p\n", conn.get()));
    4810             : 
    4811           0 :     NullHttpTransaction *nullTrans = mTransaction->QueryNullTransaction();
    4812             :     if (nullTrans) {
    4813           0 :         conn->BootstrapTimings(nullTrans->Timings());
    4814             :     }
    4815             : 
    4816             :     // Some capabilities are needed before a transaciton actually gets
    4817             :     // scheduled (e.g. how to negotiate false start)
    4818             :     conn->SetTransactionCaps(mTransaction->Caps());
    4819           0 : 
    4820             :     if (mUrgentStart) {
    4821             :         // We deliberately leave this flag unset on the connection when
    4822             :         // this half-open was not marked urgent to let the first transaction
    4823           0 :         // dispatched on the connection set it.  Then we don't need to update
    4824           0 :         // all the speculative connect APIs to pass the urgency flag while
    4825             :         // we still get nearly (if not exactly) the same result.
    4826           0 :         conn->SetUrgentStartPreferred(true);
    4827           0 :     }
    4828           0 : 
    4829           0 :     NetAddr peeraddr;
    4830             :     nsCOMPtr<nsIInterfaceRequestor> callbacks;
    4831           0 :     mTransaction->GetSecurityCallbacks(getter_AddRefs(callbacks));
    4832             :     nsresult rv;
    4833           0 :     if (out == mStreamOut) {
    4834             :         TimeDuration rtt = TimeStamp::Now() - mPrimarySynStarted;
    4835           0 :         rv = conn->Init(mEnt->mConnInfo,
    4836           0 :                         gHttpHandler->ConnMgr()->mMaxRequestDelay,
    4837           0 :                         mSocketTransport, mStreamIn, mStreamOut,
    4838           0 :                         mPrimaryConnectedOK || aFastOpen, callbacks,
    4839             :                         PR_MillisecondsToInterval(
    4840             :                           static_cast<uint32_t>(rtt.ToMilliseconds())));
    4841           0 : 
    4842           0 :         bool resetPreference = false;
    4843           0 :         mSocketTransport->GetResetIPFamilyPreference(&resetPreference);
    4844             :         if (resetPreference) {
    4845             :             mEnt->ResetIPFamilyPreference();
    4846             :         }
    4847           0 : 
    4848           0 :         if (!aFastOpen &&
    4849           0 :             NS_SUCCEEDED(mSocketTransport->GetPeerAddr(&peeraddr))) {
    4850           0 :             mEnt->RecordIPFamilyPreference(peeraddr.raw.family);
    4851             :         }
    4852           0 : 
    4853             :         // The nsHttpConnection object now owns these streams and sockets
    4854           1 :         if (!aFastOpen) {
    4855           1 :             mStreamOut = nullptr;
    4856           1 :             mStreamIn = nullptr;
    4857           1 :             mSocketTransport = nullptr;
    4858             :         } else {
    4859           1 :             conn->SetFastOpen(true);
    4860             :         }
    4861           1 :     } else if (out == mBackupStreamOut) {
    4862             :         TimeDuration rtt = TimeStamp::Now() - mBackupSynStarted;
    4863           1 :         rv = conn->Init(mEnt->mConnInfo,
    4864           1 :                         gHttpHandler->ConnMgr()->mMaxRequestDelay,
    4865           1 :                         mBackupTransport, mBackupStreamIn, mBackupStreamOut,
    4866           0 :                         mBackupConnectedOK, callbacks,
    4867             :                         PR_MillisecondsToInterval(
    4868             :                           static_cast<uint32_t>(rtt.ToMilliseconds())));
    4869           1 : 
    4870           1 :         bool resetPreference = false;
    4871             :         mBackupTransport->GetResetIPFamilyPreference(&resetPreference);
    4872             :         if (resetPreference) {
    4873             :             mEnt->ResetIPFamilyPreference();
    4874           1 :         }
    4875           1 : 
    4876           1 :         if (NS_SUCCEEDED(mBackupTransport->GetPeerAddr(&peeraddr))) {
    4877             :             mEnt->RecordIPFamilyPreference(peeraddr.raw.family);
    4878           0 :         }
    4879             : 
    4880             :         // The nsHttpConnection object now owns these streams and sockets
    4881             :         mBackupStreamOut = nullptr;
    4882           0 :         mBackupStreamIn = nullptr;
    4883           0 :         mBackupTransport = nullptr;
    4884             :     } else {
    4885             :         MOZ_ASSERT(false, "unexpected stream");
    4886             :         rv = NS_ERROR_UNEXPECTED;
    4887             :     }
    4888           0 : 
    4889           0 :     if (NS_FAILED(rv)) {
    4890             :         LOG(("nsHalfOpenSocket::SetupConn "
    4891           0 :              "conn->init (%p) failed %" PRIx32 "\n",
    4892             :              conn.get(), static_cast<uint32_t>(rv)));
    4893           0 : 
    4894             :         // Set TFO status.
    4895             :         if ((mFastOpenStatus == TFO_HTTP) ||
    4896             :             (mFastOpenStatus == TFO_DISABLED) ||
    4897             :             (mFastOpenStatus == TFO_DISABLED_CONNECT)) {
    4898             :             conn->SetFastOpenStatus(mFastOpenStatus);
    4899             :         } else {
    4900           0 :             conn->SetFastOpenStatus(TFO_INIT_FAILED);
    4901           0 :         }
    4902             :         return rv;
    4903             :     }
    4904             : 
    4905           0 :     // This half-open socket has created a connection.  This flag excludes it
    4906           0 :     // from counter of actual connections used for checking limits.
    4907           0 :     if (!aFastOpen) {
    4908             :         mHasConnected = true;
    4909             :     }
    4910           0 : 
    4911           0 :     // if this is still in the pending list, remove it and dispatch it
    4912           0 :     RefPtr<PendingTransactionInfo> pendingTransInfo = FindTransactionHelper(true);
    4913           0 :     if (pendingTransInfo) {
    4914             :         MOZ_ASSERT(!mSpeculative,
    4915             :                    "Speculative Half Open found mTransaction");
    4916             : 
    4917             :         gHttpHandler->ConnMgr()->AddActiveConn(conn, mEnt);
    4918             :         rv = gHttpHandler->ConnMgr()->DispatchTransaction(mEnt,
    4919             :                                                           pendingTransInfo->mTransaction,
    4920             :                                                           conn);
    4921           0 :     } else {
    4922             :         // this transaction was dispatched off the pending q before all the
    4923             :         // sockets established themselves.
    4924             : 
    4925             :         // After about 1 second allow for the possibility of restarting a
    4926             :         // transaction due to server close. Keep at sub 1 second as that is the
    4927             :         // minimum granularity we can expect a server to be timing out with.
    4928           0 :         conn->SetIsReusedAfter(950);
    4929           0 : 
    4930           0 :         // if we are using ssl and no other transactions are waiting right now,
    4931           0 :         // then form a null transaction to drive the SSL handshake to
    4932           0 :         // completion. Afterwards the connection will be 100% ready for the next
    4933             :         // transaction to use it. Make an exception for SSL tunneled HTTP proxy as the
    4934           0 :         // NullHttpTransaction does not know how to drive Connect
    4935           0 :         if (mEnt->mConnInfo->FirstHopSSL() &&
    4936             :             !mEnt->mUrgentStartQ.Length() &&
    4937             :             !mEnt->PendingQLength() &&
    4938           0 :             !mEnt->mConnInfo->UsingConnect()) {
    4939           0 :             LOG(("nsHalfOpenSocket::SetupConn null transaction will "
    4940             :                  "be used to finish SSL handshake on conn %p\n", conn.get()));
    4941           0 :             RefPtr<nsAHttpTransaction> trans;
    4942           0 :             if (mTransaction->IsNullTransaction() && !mDispatchedMTransaction) {
    4943             :                 // null transactions cannot be put in the entry queue, so that
    4944             :                 // explains why it is not present.
    4945           0 :                 mDispatchedMTransaction = true;
    4946             :                 trans = mTransaction;
    4947           0 :             } else {
    4948             :                 trans = new NullHttpTransaction(mEnt->mConnInfo,
    4949             :                                                 callbacks, mCaps);
    4950           0 :             }
    4951             : 
    4952           0 :             gHttpHandler->ConnMgr()->AddActiveConn(conn, mEnt);
    4953             :             rv = gHttpHandler->ConnMgr()->
    4954             :                 DispatchAbstractTransaction(mEnt, trans, mCaps, conn, 0);
    4955             :         } else {
    4956             :             // otherwise just put this in the persistent connection pool
    4957             :             LOG(("nsHalfOpenSocket::SetupConn no transaction match "
    4958             :                  "returning conn %p to pool\n", conn.get()));
    4959             :             gHttpHandler->ConnMgr()->OnMsgReclaimConnection(0, conn);
    4960             : 
    4961             :             // We expect that there is at least one tranasction in the pending
    4962             :             // queue that can take this connection, but it can happened that
    4963           0 :             // all transactions are blocked or they have took other idle
    4964           0 :             // connections. In that case the connection has been added to the
    4965           0 :             // idle queue.
    4966           0 :             // If the connection is in the idle queue but it is using ssl, make
    4967           0 :             // a nulltransaction for it to finish ssl handshake!
    4968           0 : 
    4969           0 :             // !!! It can be that mEnt is null after OnMsgReclaimConnection.!!!
    4970           0 :             if (mEnt &&
    4971           0 :                 mEnt->mConnInfo->FirstHopSSL() &&
    4972           0 :                 !mEnt->mConnInfo->UsingConnect()) {
    4973           0 :                 int32_t idx = mEnt->mIdleConns.IndexOf(conn);
    4974           0 :                 if (idx != -1) {
    4975           0 :                     DebugOnly<nsresult> rvDeb = gHttpHandler->ConnMgr()->RemoveIdleConnection(conn);
    4976             :                     MOZ_ASSERT(NS_SUCCEEDED(rvDeb));
    4977           0 :                     conn->EndIdleMonitoring();
    4978           0 :                     RefPtr<nsAHttpTransaction> trans;
    4979             :                     if (mTransaction->IsNullTransaction() &&
    4980           0 :                         !mDispatchedMTransaction) {
    4981             :                         mDispatchedMTransaction = true;
    4982           0 :                         trans = mTransaction;
    4983             :                     } else {
    4984             :                         trans = new NullHttpTransaction(mEnt->mConnInfo,
    4985             :                                                         callbacks, mCaps);
    4986             :                     }
    4987             :                     gHttpHandler->ConnMgr()->AddActiveConn(conn, mEnt);
    4988             :                     rv = gHttpHandler->ConnMgr()->
    4989             :                         DispatchAbstractTransaction(mEnt, trans, mCaps, conn, 0);
    4990           0 :                 }
    4991           0 :             }
    4992           0 :         }
    4993           0 :     }
    4994           0 : 
    4995           0 :     // If this connection has a transaction get reference to its
    4996             :     // ConnectionHandler.
    4997           0 :     if (aFastOpen) {
    4998           0 :         MOZ_ASSERT(mEnt);
    4999             :         MOZ_ASSERT(static_cast<int32_t>(mEnt->mIdleConns.IndexOf(conn)) == -1);
    5000             :         int32_t idx = mEnt->mActiveConns.IndexOf(conn);
    5001           0 :         if (NS_SUCCEEDED(rv) && (idx != -1)) {
    5002           0 :             mConnectionNegotiatingFastOpen = conn;
    5003             :         } else {
    5004           0 :             conn->SetFastOpen(false);
    5005             :             conn->SetFastOpenStatus(TFO_INIT_FAILED);
    5006             :         }
    5007             :     } else {
    5008             :         conn->SetFastOpenStatus(mFastOpenStatus);
    5009             :         if ((mFastOpenStatus != TFO_HTTP) && (mFastOpenStatus != TFO_DISABLED) &&
    5010             :             (mFastOpenStatus != TFO_DISABLED_CONNECT)) {
    5011             :             mFastOpenStatus = TFO_BACKUP_CONN; // Set this to TFO_BACKUP_CONN
    5012             :                                                // so that if a backup
    5013           0 :                                                // connection is established we
    5014           0 :                                                // do not report values twice.
    5015             :         }
    5016             :     }
    5017             : 
    5018             :     // If this halfOpenConn was speculative, but at the end the conn got a
    5019             :     // non-null transaction than this halfOpen is not speculative anymore!
    5020             :     if (conn->Transaction() && !conn->Transaction()->IsNullTransaction()) {
    5021             :         Claim();
    5022             :     }
    5023           0 : 
    5024             :     return rv;
    5025             : }
    5026             : 
    5027           0 : // register a connection to receive CanJoinConnection() for particular
    5028           0 : // origin keys
    5029           0 : void
    5030           0 : nsHttpConnectionMgr::RegisterOriginCoalescingKey(nsHttpConnection *conn,
    5031             :                                                  const nsACString &host,
    5032             :                                                  int32_t port)
    5033           0 : {
    5034           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    5035           0 :     nsHttpConnectionInfo *ci = conn ? conn->ConnectionInfo() : nullptr;
    5036           0 :     if (!ci || !conn->CanDirectlyActivate()) {
    5037           0 :         return;
    5038           0 :     }
    5039             : 
    5040           0 :     nsCString newKey;
    5041             :     BuildOriginFrameHashKey(newKey, ci, host, port);
    5042           0 :     nsTArray<nsWeakPtr> *listOfWeakConns =  mCoalescingHash.Get(newKey);
    5043             :     if (!listOfWeakConns) {
    5044             :         listOfWeakConns = new nsTArray<nsWeakPtr>(1);
    5045             :         mCoalescingHash.Put(newKey, listOfWeakConns);
    5046             :     }
    5047             :     listOfWeakConns->AppendElement(do_GetWeakReference(static_cast<nsISupportsWeakReference*>(conn)));
    5048             : 
    5049           0 :     LOG(("nsHttpConnectionMgr::RegisterOriginCoalescingKey "
    5050             :          "Established New Coalescing Key %s to %p %s\n",
    5051             :          newKey.get(), conn, ci->HashKey().get()));
    5052             : }
    5053             : 
    5054           0 : // method for nsITransportEventSink
    5055             : NS_IMETHODIMP
    5056           0 : nsHttpConnectionMgr::nsHalfOpenSocket::OnTransportStatus(nsITransport *trans,
    5057           0 :                                                          nsresult status,
    5058           0 :                                                          int64_t progress,
    5059           0 :                                                          int64_t progressMax)
    5060           1 : {
    5061           1 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    5062             : 
    5063             :     MOZ_ASSERT((trans == mSocketTransport) || (trans == mBackupTransport));
    5064             :     MOZ_ASSERT(mEnt);
    5065             :     if (mTransaction) {
    5066             :         if ((trans == mSocketTransport) ||
    5067             :             ((trans == mBackupTransport) && (status == NS_NET_STATUS_CONNECTED_TO) &&
    5068             :              mSocketTransport)) {
    5069             :             // Send this status event only if the transaction is still pending,
    5070             :             // i.e. it has not found a free already connected socket.
    5071           0 :             // Sockets in halfOpen state can only get following events:
    5072             :             // NS_NET_STATUS_RESOLVING_HOST, NS_NET_STATUS_RESOLVED_HOST,
    5073             :             // NS_NET_STATUS_CONNECTING_TO and NS_NET_STATUS_CONNECTED_TO.
    5074             :             // mBackupTransport is only started after
    5075           0 :             // NS_NET_STATUS_CONNECTING_TO of mSocketTransport, so ignore all
    5076           0 :             // mBackupTransport events until NS_NET_STATUS_CONNECTED_TO.
    5077           0 :             // mBackupTransport must be connected before mSocketTransport.
    5078           0 :             mTransaction->OnTransportStatus(trans, status, progress);
    5079             :         }
    5080           1 :     }
    5081             : 
    5082             :     MOZ_ASSERT(trans == mSocketTransport || trans == mBackupTransport);
    5083             :     if (status == NS_NET_STATUS_CONNECTED_TO) {
    5084             :         if (trans == mSocketTransport) {
    5085           0 :             mPrimaryConnectedOK = true;
    5086             :         } else {
    5087             :             mBackupConnectedOK = true;
    5088             :         }
    5089           0 :     }
    5090             : 
    5091             :     // The rest of this method only applies to the primary transport
    5092             :     if (trans != mSocketTransport) {
    5093             :         return NS_OK;
    5094             :     }
    5095             : 
    5096           0 :     mPrimaryStreamStatus = status;
    5097           0 : 
    5098           0 :     // if we are doing spdy coalescing and haven't recorded the ip address
    5099           0 :     // for this entry before then make the hash key if our dns lookup
    5100           0 :     // just completed. We can't do coalescing if using a proxy because the
    5101           0 :     // ip addresses are not available to the client.
    5102             : 
    5103           0 :     if (status == NS_NET_STATUS_CONNECTING_TO &&
    5104           0 :         gHttpHandler->IsSpdyEnabled() &&
    5105           0 :         gHttpHandler->CoalesceSpdy() &&
    5106           0 :         mEnt && mEnt->mConnInfo && mEnt->mConnInfo->EndToEndSSL() &&
    5107           0 :         !mEnt->mConnInfo->UsingProxy() &&
    5108             :         mEnt->mCoalescingKeys.IsEmpty()) {
    5109             : 
    5110           0 :         nsCOMPtr<nsIDNSRecord> dnsRecord(do_GetInterface(mSocketTransport));
    5111           0 :         nsTArray<NetAddr> addressSet;
    5112           0 :         nsresult rv = NS_ERROR_NOT_AVAILABLE;
    5113           0 :         if (dnsRecord) {
    5114           0 :             rv = dnsRecord->GetAddresses(addressSet);
    5115           0 :         }
    5116           0 : 
    5117           0 :         if (NS_SUCCEEDED(rv) && !addressSet.IsEmpty()) {
    5118             :             for (uint32_t i = 0; i < addressSet.Length(); ++i) {
    5119           0 :                 nsCString *newKey = mEnt->mCoalescingKeys.AppendElement(nsCString());
    5120             :                 newKey->SetCapacity(kIPv6CStrBufSize + 26);
    5121           0 :                 NetAddrToString(&addressSet[i], newKey->BeginWriting(), kIPv6CStrBufSize);
    5122           0 :                 newKey->SetLength(strlen(newKey->BeginReading()));
    5123           0 :                 if (mEnt->mConnInfo->GetAnonymous()) {
    5124           0 :                     newKey->AppendLiteral("~A:");
    5125           0 :                 } else {
    5126           0 :                     newKey->AppendLiteral("~.:");
    5127           0 :                 }
    5128             :                 newKey->AppendInt(mEnt->mConnInfo->OriginPort());
    5129             :                 newKey->AppendLiteral("/[");
    5130             :                 nsAutoCString suffix;
    5131           0 :                 mEnt->mConnInfo->GetOriginAttributes().CreateSuffix(suffix);
    5132             :                 newKey->Append(suffix);
    5133             :                 newKey->AppendLiteral("]viaDNS");
    5134             :                 LOG(("nsHttpConnectionMgr::nsHalfOpenSocket::OnTransportStatus "
    5135           0 :                      "STATUS_CONNECTING_TO Established New Coalescing Key # %d for host "
    5136             :                      "%s [%s]", i, mEnt->mConnInfo->Origin(), newKey->get()));
    5137             :             }
    5138             :             gHttpHandler->ConnMgr()->ProcessSpdyPendingQ(mEnt);
    5139             :         }
    5140             :     }
    5141             : 
    5142             :     switch (status) {
    5143             :     case NS_NET_STATUS_CONNECTING_TO:
    5144             :         // Passed DNS resolution, now trying to connect, start the backup timer
    5145           0 :         // only prevent creating another backup transport.
    5146           0 :         // We also check for mEnt presence to not instantiate the timer after
    5147             :         // this half open socket has already been abandoned.  It may happen
    5148             :         // when we get this notification right between main-thread calls to
    5149             :         // nsHttpConnectionMgr::Shutdown and nsSocketTransportService::Shutdown
    5150             :         // where the first abandons all half open socket instances and only
    5151             :         // after that the second stops the socket thread.
    5152           0 :         if (mEnt && !mBackupTransport && !mSynTimer)
    5153           0 :             SetupBackupTimer();
    5154             :         break;
    5155             : 
    5156             :     case NS_NET_STATUS_CONNECTED_TO:
    5157             :         // TCP connection's up, now transfer or SSL negotiantion starts,
    5158             :         // no need for backup socket
    5159             :         CancelBackupTimer();
    5160             :         break;
    5161             : 
    5162             :     default:
    5163             :         break;
    5164           0 :     }
    5165             : 
    5166             :     return NS_OK;
    5167           0 : }
    5168           0 : 
    5169           0 : // method for nsIInterfaceRequestor
    5170           0 : NS_IMETHODIMP
    5171           0 : nsHttpConnectionMgr::nsHalfOpenSocket::GetInterface(const nsIID &iid,
    5172             :                                                     void **result)
    5173             : {
    5174             :     if (mTransaction) {
    5175             :         nsCOMPtr<nsIInterfaceRequestor> callbacks;
    5176             :         mTransaction->GetSecurityCallbacks(getter_AddRefs(callbacks));
    5177           0 :         if (callbacks)
    5178             :             return callbacks->GetInterface(iid, result);
    5179             :     }
    5180             :     return NS_ERROR_NO_INTERFACE;
    5181           0 : }
    5182             : 
    5183             : bool
    5184             : nsHttpConnectionMgr::nsHalfOpenSocket::AcceptsTransaction(nsHttpTransaction * trans)
    5185           0 : {
    5186             :     // When marked as urgent start, only accept urgent start marked transactions.
    5187           0 :     // Otherwise, accept any kind of transaction.
    5188           0 :     return !mUrgentStart || (trans->Caps() & nsIClassOfService::UrgentStart);
    5189             : }
    5190           0 : 
    5191           0 : bool
    5192           0 : nsHttpConnectionMgr::nsHalfOpenSocket::Claim()
    5193             : {
    5194             :     if (mSpeculative) {
    5195           0 :         mSpeculative = false;
    5196           0 :         uint32_t flags;
    5197             :         if (mSocketTransport && NS_SUCCEEDED(mSocketTransport->GetConnectionFlags(&flags))) {
    5198           0 :             flags &= ~nsISocketTransport::DISABLE_RFC1918;
    5199           0 :             mSocketTransport->SetConnectionFlags(flags);
    5200           0 :         }
    5201             : 
    5202             :         Telemetry::AutoCounter<Telemetry::HTTPCONNMGR_USED_SPECULATIVE_CONN> usedSpeculativeConn;
    5203           0 :         ++usedSpeculativeConn;
    5204           0 : 
    5205           0 :         if (mIsFromPredictor) {
    5206             :             Telemetry::AutoCounter<Telemetry::PREDICTOR_TOTAL_PRECONNECTS_USED> totalPreconnectsUsed;
    5207             :             ++totalPreconnectsUsed;
    5208             :         }
    5209           0 : 
    5210           0 :         if ((mPrimaryStreamStatus == NS_NET_STATUS_CONNECTING_TO) &&
    5211           0 :             mEnt && !mBackupTransport && !mSynTimer) {
    5212             :             SetupBackupTimer();
    5213             :         }
    5214             :     }
    5215             : 
    5216             :     if (mFreeToUse) {
    5217           0 :         mFreeToUse = false;
    5218             :         return true;
    5219           0 :     }
    5220             :     return false;
    5221             : }
    5222             : 
    5223           0 : void
    5224           0 : nsHttpConnectionMgr::nsHalfOpenSocket::Unclaim()
    5225             : {
    5226             :     MOZ_ASSERT(!mSpeculative && !mFreeToUse);
    5227           0 :     // We will keep the backup-timer running. Most probably this halfOpen will
    5228             :     // be used by a transaction from which this transaction took the halfOpen.
    5229             :     // (this is happening because of the transaction priority.)
    5230             :     mFreeToUse = true;
    5231           0 : }
    5232           0 : 
    5233             : already_AddRefed<nsHttpConnection>
    5234             : ConnectionHandle::TakeHttpConnection()
    5235             : {
    5236           0 :     // return our connection object to the caller and clear it internally
    5237             :     // do not drop our reference - the caller now owns it.
    5238           0 :     MOZ_ASSERT(mConn);
    5239           0 :     return mConn.forget();
    5240             : }
    5241             : 
    5242             : already_AddRefed<nsHttpConnection>
    5243           0 : ConnectionHandle::HttpConnection()
    5244             : {
    5245             :     RefPtr<nsHttpConnection> rv(mConn);
    5246           0 :     return rv.forget();
    5247             : }
    5248             : 
    5249             : void
    5250           0 : ConnectionHandle::TopLevelOuterContentWindowIdChanged(uint64_t windowId)
    5251           0 : {
    5252             :   // Do nothing.
    5253             : }
    5254             : 
    5255             : // nsConnectionEntry
    5256             : 
    5257           0 : nsHttpConnectionMgr::
    5258             : nsConnectionEntry::nsConnectionEntry(nsHttpConnectionInfo *ci)
    5259           0 :     : mConnInfo(ci)
    5260             :     , mUsingSpdy(false)
    5261           0 :     , mPreferIPv4(false)
    5262           0 :     , mPreferIPv6(false)
    5263             :     , mUsedForConnection(false)
    5264             :     , mDoNotDestroy(false)
    5265           0 : {
    5266             :     MOZ_COUNT_CTOR(nsConnectionEntry);
    5267             : 
    5268           0 :     if (mConnInfo->FirstHopSSL()) {
    5269             :         mUseFastOpen = gHttpHandler->UseFastOpen();
    5270           0 :     } else {
    5271             :         // Only allow the TCP fast open on a secure connection.
    5272             :         mUseFastOpen = false;
    5273           0 :     }
    5274             : 
    5275           0 :     LOG(("nsConnectionEntry::nsConnectionEntry this=%p key=%s",
    5276             :          this, ci->HashKey().get()));
    5277             : }
    5278             : 
    5279             : bool
    5280           0 : nsHttpConnectionMgr::nsConnectionEntry::AvailableForDispatchNow()
    5281             : {
    5282             :     if (mIdleConns.Length() && mIdleConns[0]->CanReuse()) {
    5283             :         return true;
    5284           0 :     }
    5285             : 
    5286           0 :     return gHttpHandler->ConnMgr()->
    5287           0 :         GetSpdyActiveConn(this) ? true : false;
    5288             : }
    5289           0 : 
    5290           0 : bool
    5291             : nsHttpConnectionMgr::GetConnectionData(nsTArray<HttpRetParams> *aArg)
    5292             : {
    5293           0 :     for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
    5294           0 :         RefPtr<nsConnectionEntry> ent = iter.Data();
    5295           0 : 
    5296           0 :         if (ent->mConnInfo->GetPrivate()) {
    5297           0 :             continue;
    5298           0 :         }
    5299           0 : 
    5300           0 :         HttpRetParams data;
    5301           0 :         data.host = ent->mConnInfo->Origin();
    5302           0 :         data.port = ent->mConnInfo->OriginPort();
    5303             :         for (uint32_t i = 0; i < ent->mActiveConns.Length(); i++) {
    5304           0 :             HttpConnInfo info;
    5305           0 :             info.ttl = ent->mActiveConns[i]->TimeToLive();
    5306             :             info.rtt = ent->mActiveConns[i]->Rtt();
    5307           0 :             if (ent->mActiveConns[i]->UsingSpdy()) {
    5308             :                 info.SetHTTP2ProtocolVersion(
    5309           0 :                     ent->mActiveConns[i]->GetSpdyVersion());
    5310           0 :             } else {
    5311           0 :                 info.SetHTTP1ProtocolVersion(
    5312           0 :                     ent->mActiveConns[i]->GetLastHttpResponseVersion());
    5313           0 :             }
    5314           0 :             data.active.AppendElement(info);
    5315           0 :         }
    5316             :         for (uint32_t i = 0; i < ent->mIdleConns.Length(); i++) {
    5317           0 :             HttpConnInfo info;
    5318             :             info.ttl = ent->mIdleConns[i]->TimeToLive();
    5319           0 :             info.rtt = ent->mIdleConns[i]->Rtt();
    5320           0 :             info.SetHTTP1ProtocolVersion(
    5321             :                 ent->mIdleConns[i]->GetLastHttpResponseVersion());
    5322           0 :             data.idle.AppendElement(info);
    5323           0 :         }
    5324           0 :         for (uint32_t i = 0; i < ent->mHalfOpens.Length(); i++) {
    5325             :             HalfOpenSockets hSocket;
    5326             :             hSocket.speculative = ent->mHalfOpens[i]->IsSpeculative();
    5327           0 :             data.halfOpens.AppendElement(hSocket);
    5328             :         }
    5329             :         data.spdy = ent->mUsingSpdy;
    5330             :         data.ssl = ent->mConnInfo->EndToEndSSL();
    5331           0 :         aArg->AppendElement(data);
    5332             :     }
    5333           0 : 
    5334           0 :     return true;
    5335           0 : }
    5336           0 : 
    5337             : void
    5338           0 : nsHttpConnectionMgr::ResetIPFamilyPreference(nsHttpConnectionInfo *ci)
    5339             : {
    5340             :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    5341           0 :     nsConnectionEntry *ent = mCT.GetWeak(ci->HashKey());
    5342             :     if (ent) {
    5343             :         ent->ResetIPFamilyPreference();
    5344           0 :     }
    5345           0 : }
    5346           0 : 
    5347           0 : uint32_t
    5348             : nsHttpConnectionMgr::
    5349           0 : nsConnectionEntry::UnconnectedHalfOpens()
    5350             : {
    5351             :     uint32_t unconnectedHalfOpens = 0;
    5352             :     for (uint32_t i = 0; i < mHalfOpens.Length(); ++i) {
    5353           0 :         if (!mHalfOpens[i]->HasConnected())
    5354             :             ++unconnectedHalfOpens;
    5355             :     }
    5356             :     return unconnectedHalfOpens;
    5357             : }
    5358           0 : 
    5359             : void
    5360           0 : nsHttpConnectionMgr::
    5361           0 : nsConnectionEntry::RemoveHalfOpen(nsHalfOpenSocket *halfOpen)
    5362           0 : {
    5363             :     // A failure to create the transport object at all
    5364           0 :     // will result in it not being present in the halfopen table. That's expected.
    5365           0 :     if (mHalfOpens.RemoveElement(halfOpen)) {
    5366           0 : 
    5367             :         if (halfOpen->IsSpeculative()) {
    5368             :             Telemetry::AutoCounter<Telemetry::HTTPCONNMGR_UNUSED_SPECULATIVE_CONN> unusedSpeculativeConn;
    5369             :             ++unusedSpeculativeConn;
    5370           0 : 
    5371           0 :             if (halfOpen->IsFromPredictor()) {
    5372           0 :                 Telemetry::AutoCounter<Telemetry::PREDICTOR_TOTAL_PRECONNECTS_UNUSED> totalPreconnectsUnused;
    5373             :                 ++totalPreconnectsUnused;
    5374             :             }
    5375           0 :         }
    5376             : 
    5377             :         MOZ_ASSERT(gHttpHandler->ConnMgr()->mNumHalfOpenConns);
    5378           0 :         if (gHttpHandler->ConnMgr()->mNumHalfOpenConns) { // just in case
    5379             :             gHttpHandler->ConnMgr()->mNumHalfOpenConns--;
    5380             :         }
    5381             :     } else {
    5382           0 :         mHalfOpenFastOpenBackups.RemoveElement(halfOpen);
    5383           0 :     }
    5384           0 : 
    5385             :     if (!UnconnectedHalfOpens()) {
    5386             :         // perhaps this reverted RestrictConnections()
    5387             :         // use the PostEvent version of processpendingq to avoid
    5388           0 :         // altering the pending q vector from an arbitrary stack
    5389             :         nsresult rv = gHttpHandler->ConnMgr()->ProcessPendingQ(mConnInfo);
    5390             :         if (NS_FAILED(rv)) {
    5391           0 :             LOG(("nsHttpConnectionMgr::nsConnectionEntry::RemoveHalfOpen\n"
    5392             :                  "    failed to process pending queue\n"));
    5393             :         }
    5394           0 :     }
    5395             : }
    5396           0 : 
    5397           0 : void
    5398             : nsHttpConnectionMgr::
    5399             : nsConnectionEntry::RecordIPFamilyPreference(uint16_t family)
    5400           0 : {
    5401           0 :   LOG(("nsConnectionEntry::RecordIPFamilyPreference %p, af=%u", this, family));
    5402             : 
    5403             :   if (family == PR_AF_INET && !mPreferIPv6) {
    5404           0 :     mPreferIPv4 = true;
    5405           0 :   }
    5406             : 
    5407             :   if (family == PR_AF_INET6 && !mPreferIPv4) {
    5408           0 :     mPreferIPv6 = true;
    5409             :   }
    5410             : 
    5411           0 :   LOG(("  %p prefer ipv4=%d, ipv6=%d", this, (bool)mPreferIPv4, (bool)mPreferIPv6));
    5412             : }
    5413           0 : 
    5414           0 : void
    5415           0 : nsHttpConnectionMgr::
    5416             : nsConnectionEntry::ResetIPFamilyPreference()
    5417           0 : {
    5418             :   LOG(("nsConnectionEntry::ResetIPFamilyPreference %p", this));
    5419           0 : 
    5420             :   mPreferIPv4 = false;
    5421             :   mPreferIPv6 = false;
    5422             : }
    5423           0 : 
    5424             : bool net::nsHttpConnectionMgr::nsConnectionEntry::PreferenceKnown() const
    5425           0 : {
    5426           0 :   return (bool)mPreferIPv4 || (bool)mPreferIPv6;
    5427           0 : }
    5428             : 
    5429             : size_t
    5430           0 : nsHttpConnectionMgr::nsConnectionEntry::PendingQLength() const
    5431             : {
    5432             :   size_t length = 0;
    5433             :   for (auto it = mPendingTransactionTable.ConstIter(); !it.Done(); it.Next()) {
    5434           0 :     length += it.UserData()->Length();
    5435             :   }
    5436             : 
    5437             :   return length;
    5438           0 : }
    5439             : 
    5440             : void
    5441             : nsHttpConnectionMgr::
    5442             : nsConnectionEntry::InsertTransaction(PendingTransactionInfo *info,
    5443           0 :                                      bool aInsertAsFirstForTheSamePriority /*= false*/)
    5444             : {
    5445           0 :   LOG(("nsHttpConnectionMgr::nsConnectionEntry::InsertTransaction"
    5446           0 :        " trans=%p, windowId=%" PRIu64 "\n",
    5447           0 :        info->mTransaction.get(),
    5448             :        info->mTransaction->TopLevelOuterContentWindowId()));
    5449             : 
    5450           0 :   uint64_t windowId = TabIdForQueuing(info->mTransaction);
    5451           0 :   nsTArray<RefPtr<PendingTransactionInfo>> *infoArray;
    5452           0 :   if (!mPendingTransactionTable.Get(windowId, &infoArray)) {
    5453             :     infoArray = new nsTArray<RefPtr<PendingTransactionInfo>>();
    5454             :     mPendingTransactionTable.Put(windowId, infoArray);
    5455           0 :   }
    5456             : 
    5457             :   gHttpHandler->ConnMgr()->InsertTransactionSorted(*infoArray, info,
    5458             :                                                    aInsertAsFirstForTheSamePriority);
    5459             : }
    5460             : 
    5461           0 : void
    5462           0 : nsHttpConnectionMgr::
    5463           0 : nsConnectionEntry::AppendPendingQForFocusedWindow(
    5464           0 :     uint64_t windowId,
    5465             :     nsTArray<RefPtr<PendingTransactionInfo>> &result,
    5466             :     uint32_t maxCount)
    5467           0 : {
    5468           0 :     nsTArray<RefPtr<PendingTransactionInfo>> *infoArray = nullptr;
    5469           0 :     if (!mPendingTransactionTable.Get(windowId, &infoArray)) {
    5470           0 :         result.Clear();
    5471           0 :         return;
    5472             :     }
    5473           0 : 
    5474           0 :     uint32_t countToAppend = maxCount;
    5475           0 :     countToAppend =
    5476           0 :         countToAppend > infoArray->Length() || countToAppend == 0 ?
    5477             :             infoArray->Length() :
    5478           0 :             countToAppend;
    5479             : 
    5480             :     result.InsertElementsAt(result.Length(),
    5481             :                             infoArray->Elements(),
    5482             :                             countToAppend);
    5483             :     infoArray->RemoveElementsAt(0, countToAppend);
    5484             : 
    5485           0 :     LOG(("nsConnectionEntry::AppendPendingQForFocusedWindow [ci=%s], "
    5486             :          "pendingQ count=%zu window.count=%zu for focused window (id=%" PRIu64 ")\n",
    5487             :          mConnInfo->HashKey().get(), result.Length(), infoArray->Length(),
    5488             :          windowId));
    5489             : }
    5490             : 
    5491             : void
    5492           0 : nsHttpConnectionMgr::
    5493           0 : nsConnectionEntry::AppendPendingQForNonFocusedWindows(
    5494           0 :     uint64_t windowId,
    5495             :     nsTArray<RefPtr<PendingTransactionInfo>> &result,
    5496             :     uint32_t maxCount)
    5497             : {
    5498             :     // XXX Adjust the order of transactions in a smarter manner.
    5499           0 :     uint32_t totalCount = 0;
    5500           0 :     for (auto it = mPendingTransactionTable.Iter(); !it.Done(); it.Next()) {
    5501             :         if (windowId && it.Key() == windowId) {
    5502             :             continue;
    5503             :         }
    5504             : 
    5505             :         uint32_t count = 0;
    5506           0 :         for (; count < it.UserData()->Length(); ++count) {
    5507             :             if (maxCount && totalCount == maxCount) {
    5508           0 :                 break;
    5509           0 :             }
    5510             : 
    5511           0 :             // Because elements in |result| could come from multiple penndingQ,
    5512             :             // call |InsertTransactionSorted| to make sure the order is correct.
    5513           0 :             gHttpHandler->ConnMgr()->InsertTransactionSorted(
    5514           0 :                 result,
    5515             :                 it.UserData()->ElementAt(count));
    5516             :             ++totalCount;
    5517             :         }
    5518           0 :         it.UserData()->RemoveElementsAt(0, count);
    5519             : 
    5520             :         if (maxCount && totalCount == maxCount) {
    5521             :             if (it.UserData()->Length()) {
    5522             :                 // There are still some pending transactions for background
    5523             :                 // tabs but we limit their dispatch.  This is considered as
    5524           0 :                 // an active tab optimization.
    5525             :                 nsHttp::NotifyActiveTabLoadOptimization();
    5526             :             }
    5527           0 :             break;
    5528             :         }
    5529             :     }
    5530           0 : 
    5531             :     LOG(("nsConnectionEntry::AppendPendingQForNonFocusedWindows [ci=%s], "
    5532           0 :          "pendingQ count=%zu for non focused window\n",
    5533           0 :          mConnInfo->HashKey().get(), result.Length()));
    5534           0 : }
    5535             : 
    5536             : void
    5537           0 : nsHttpConnectionMgr::nsConnectionEntry::RemoveEmptyPendingQ()
    5538             : {
    5539             :     for (auto it = mPendingTransactionTable.Iter(); !it.Done(); it.Next()) {
    5540           0 :         if (it.UserData()->IsEmpty()) {
    5541             :             it.Remove();
    5542             :         }
    5543             :     }
    5544           0 : }
    5545           0 : 
    5546             : void
    5547           0 : nsHttpConnectionMgr::MoveToWildCardConnEntry(nsHttpConnectionInfo *specificCI,
    5548             :                                              nsHttpConnectionInfo *wildCardCI,
    5549             :                                              nsHttpConnection *proxyConn)
    5550             : {
    5551           0 :     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    5552           0 :     MOZ_ASSERT(specificCI->UsingHttpsProxy());
    5553             : 
    5554             :     LOG(("nsHttpConnectionMgr::MakeConnEntryWildCard conn %p has requested to "
    5555           0 :          "change CI from %s to %s\n", proxyConn, specificCI->HashKey().get(),
    5556           0 :          wildCardCI->HashKey().get()));
    5557             : 
    5558             :     nsConnectionEntry *ent = mCT.GetWeak(specificCI->HashKey());
    5559           0 :     LOG(("nsHttpConnectionMgr::MakeConnEntryWildCard conn %p using ent %p (spdy %d)\n",
    5560           0 :          proxyConn, ent, ent ? ent->mUsingSpdy : 0));
    5561             : 
    5562             :     if (!ent || !ent->mUsingSpdy) {
    5563             :         return;
    5564           0 :     }
    5565             : 
    5566           0 :     nsConnectionEntry *wcEnt = GetOrCreateConnectionEntry(wildCardCI, true);
    5567             :     if (wcEnt == ent) {
    5568             :         // nothing to do!
    5569             :         return;
    5570             :     }
    5571           0 :     wcEnt->mUsingSpdy = true;
    5572             : 
    5573             :     LOG(("nsHttpConnectionMgr::MakeConnEntryWildCard ent %p "
    5574             :          "idle=%zu active=%zu half=%zu pending=%zu\n",
    5575             :          ent, ent->mIdleConns.Length(), ent->mActiveConns.Length(),
    5576           0 :          ent->mHalfOpens.Length(), ent->PendingQLength()));
    5577           0 : 
    5578           0 :     LOG(("nsHttpConnectionMgr::MakeConnEntryWildCard wc-ent %p "
    5579           0 :          "idle=%zu active=%zu half=%zu pending=%zu\n",
    5580           0 :          wcEnt, wcEnt->mIdleConns.Length(), wcEnt->mActiveConns.Length(),
    5581           0 :          wcEnt->mHalfOpens.Length(), wcEnt->PendingQLength()));
    5582           0 : 
    5583             :     int32_t count = ent->mActiveConns.Length();
    5584             :     RefPtr<nsHttpConnection> deleteProtector(proxyConn);
    5585             :     for (int32_t i = 0; i < count; ++i) {
    5586           0 :         if (ent->mActiveConns[i] == proxyConn) {
    5587           0 :             ent->mActiveConns.RemoveElementAt(i);
    5588           0 :             wcEnt->mActiveConns.InsertElementAt(0, proxyConn);
    5589           0 :             return;
    5590           0 :         }
    5591           0 :     }
    5592             : 
    5593             :     count = ent->mIdleConns.Length();
    5594             :     for (int32_t i = 0; i < count; ++i) {
    5595             :         if (ent->mIdleConns[i] == proxyConn) {
    5596             :             ent->mIdleConns.RemoveElementAt(i);
    5597             :             wcEnt->mIdleConns.InsertElementAt(0, proxyConn);
    5598             :             return;
    5599             :         }
    5600             :     }
    5601             : }
    5602             : 
    5603             : } // namespace net
    5604             : } // namespace mozilla

Generated by: LCOV version 1.13-14-ga5dd952