summaryrefslogtreecommitdiff
path: root/netwerk/protocol/http/nsHttpConnectionMgr.h
blob: a2c88c4028c2a13a3fd3e6f0df58c2c164077b1b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
/* vim:set ts=4 sw=4 sts=4 et cin: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsHttpConnectionMgr_h__
#define nsHttpConnectionMgr_h__

#include "nsHttpConnection.h"
#include "nsHttpTransaction.h"
#include "nsTArray.h"
#include "nsThreadUtils.h"
#include "nsClassHashtable.h"
#include "nsDataHashtable.h"
#include "nsAutoPtr.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Attributes.h"
#include "AlternateServices.h"
#include "ARefBase.h"

#include "nsIObserver.h"
#include "nsITimer.h"

class nsIHttpUpgradeListener;

namespace mozilla {
namespace net {
class EventTokenBucket;
class NullHttpTransaction;
struct HttpRetParams;

//-----------------------------------------------------------------------------

// message handlers have this signature
class nsHttpConnectionMgr;
typedef void (nsHttpConnectionMgr:: *nsConnEventHandler)(int32_t, ARefBase *);

class nsHttpConnectionMgr final : public nsIObserver
                                , public AltSvcCache
{
public:
    NS_DECL_THREADSAFE_ISUPPORTS
    NS_DECL_NSIOBSERVER

    // parameter names
    enum nsParamName {
        MAX_CONNECTIONS,
        MAX_PERSISTENT_CONNECTIONS_PER_HOST,
        MAX_PERSISTENT_CONNECTIONS_PER_PROXY,
        MAX_REQUEST_DELAY,
        MAX_PIPELINED_REQUESTS,
        MAX_OPTIMISTIC_PIPELINED_REQUESTS
    };

    //-------------------------------------------------------------------------
    // NOTE: functions below may only be called on the main thread.
    //-------------------------------------------------------------------------

    nsHttpConnectionMgr();

    nsresult Init(uint16_t maxConnections,
                  uint16_t maxPersistentConnectionsPerHost,
                  uint16_t maxPersistentConnectionsPerProxy,
                  uint16_t maxRequestDelay,
                  uint16_t maxPipelinedRequests,
                  uint16_t maxOptimisticPipelinedRequests);
    nsresult Shutdown();

    //-------------------------------------------------------------------------
    // NOTE: functions below may be called on any thread.
    //-------------------------------------------------------------------------

    // Schedules next pruning of dead connection to happen after
    // given time.
    void PruneDeadConnectionsAfter(uint32_t time);

    // Stops timer scheduled for next pruning of dead connections if
    // there are no more idle connections or active spdy ones
    void ConditionallyStopPruneDeadConnectionsTimer();

    // Stops timer used for the read timeout tick if there are no currently
    // active connections.
    void ConditionallyStopTimeoutTick();

    // adds a transaction to the list of managed transactions.
    nsresult AddTransaction(nsHttpTransaction *, int32_t priority);

    // called to reschedule the given transaction.  it must already have been
    // added to the connection manager via AddTransaction.
    nsresult RescheduleTransaction(nsHttpTransaction *, int32_t priority);

    // cancels a transaction w/ the given reason.
    nsresult CancelTransaction(nsHttpTransaction *, nsresult reason);
    nsresult CancelTransactions(nsHttpConnectionInfo *, nsresult reason);

    // called to force the connection manager to prune its list of idle
    // connections.
    nsresult PruneDeadConnections();

    // called to close active connections with no registered "traffic"
    nsresult PruneNoTraffic();

    // "VerifyTraffic" means marking connections now, and then check again in
    // N seconds to see if there's been any traffic and if not, kill
    // that connection.
    nsresult VerifyTraffic();

    // Close all idle persistent connections and prevent any active connections
    // from being reused. Optional connection info resets CI specific
    // information such as Happy Eyeballs history.
    nsresult DoShiftReloadConnectionCleanup(nsHttpConnectionInfo *);

    // called to get a reference to the socket transport service.  the socket
    // transport service is not available when the connection manager is down.
    nsresult GetSocketThreadTarget(nsIEventTarget **);

    // called to indicate a transaction for the connectionInfo is likely coming
    // soon. The connection manager may use this information to start a TCP
    // and/or SSL level handshake for that resource immediately so that it is
    // ready when the transaction is submitted. No obligation is taken on by the
    // connection manager, nor is the submitter obligated to actually submit a
    // real transaction for this connectionInfo.
    nsresult SpeculativeConnect(nsHttpConnectionInfo *,
                                nsIInterfaceRequestor *,
                                uint32_t caps = 0,
                                NullHttpTransaction * = nullptr);

    // called when a connection is done processing a transaction.  if the
    // connection can be reused then it will be added to the idle list, else
    // it will be closed.
    nsresult ReclaimConnection(nsHttpConnection *conn);

    // called by the main thread to execute the taketransport() logic on the
    // socket thread after a 101 response has been received and the socket
    // needs to be transferred to an expectant upgrade listener such as
    // websockets.
    nsresult CompleteUpgrade(nsAHttpConnection *aConn,
                             nsIHttpUpgradeListener *aUpgradeListener);

    // called to update a parameter after the connection manager has already
    // been initialized.
    nsresult UpdateParam(nsParamName name, uint16_t value);

    // called from main thread to post a new request token bucket
    // to the socket thread
    nsresult UpdateRequestTokenBucket(EventTokenBucket *aBucket);

    // clears the connection history mCT
    nsresult ClearConnectionHistory();

    // Pipielining Interfaces and Datatypes

    const static uint32_t kPipelineInfoTypeMask = 0xffff0000;
    const static uint32_t kPipelineInfoIDMask   = ~kPipelineInfoTypeMask;

    const static uint32_t kPipelineInfoTypeRed     = 0x00010000;
    const static uint32_t kPipelineInfoTypeBad     = 0x00020000;
    const static uint32_t kPipelineInfoTypeNeutral = 0x00040000;
    const static uint32_t kPipelineInfoTypeGood    = 0x00080000;

    enum PipelineFeedbackInfoType
    {
        // Used when an HTTP response less than 1.1 is received
        RedVersionTooLow = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0001,

        // Used when a HTTP Server response header that is on the banned from
        // pipelining list is received
        RedBannedServer = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0002,

        // Used when a response is terminated early, when it fails an
        // integrity check such as assoc-req or when a 304 contained a Last-Modified
        // differnet than the entry being validated.
        RedCorruptedContent = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0004,

        // Used when a pipeline is only partly satisfied - for instance if the
        // server closed the connection after responding to the first
        // request but left some requests unprocessed.
        RedCanceledPipeline = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0005,

        // Used when a connection that we expected to stay persistently open
        // was closed by the server. Not used when simply timed out.
        BadExplicitClose = kPipelineInfoTypeBad | 0x0003,

        // Used when there is a gap of around 400 - 1200ms in between data being
        // read from the server
        BadSlowReadMinor = kPipelineInfoTypeBad | 0x0006,

        // Used when there is a gap of > 1200ms in between data being
        // read from the server
        BadSlowReadMajor = kPipelineInfoTypeBad | 0x0007,

        // Used when a response is received that is not framed with either chunked
        // encoding or a complete content length.
        BadInsufficientFraming = kPipelineInfoTypeBad | 0x0008,

        // Used when a very large response is recevied in a potential pipelining
        // context. Large responses cause head of line blocking.
        BadUnexpectedLarge = kPipelineInfoTypeBad | 0x000B,

        // Used when a response is received that has headers that appear to support
        // pipelining.
        NeutralExpectedOK = kPipelineInfoTypeNeutral | 0x0009,

        // Used when a response is received successfully to a pipelined request.
        GoodCompletedOK = kPipelineInfoTypeGood | 0x000A
    };

    // called to provide information relevant to the pipelining manager
    // may be called from any thread
    void     PipelineFeedbackInfo(nsHttpConnectionInfo *,
                                  PipelineFeedbackInfoType info,
                                  nsHttpConnection *,
                                  uint32_t);

    void ReportFailedToProcess(nsIURI *uri);

    // Causes a large amount of connection diagnostic information to be
    // printed to the javascript console
    void PrintDiagnostics();

    //-------------------------------------------------------------------------
    // NOTE: functions below may be called only on the socket thread.
    //-------------------------------------------------------------------------

    // called to change the connection entry associated with conn from specific into
    // a wildcard (i.e. http2 proxy friendy) mapping
    void MoveToWildCardConnEntry(nsHttpConnectionInfo *specificCI,
                                 nsHttpConnectionInfo *wildcardCI,
                                 nsHttpConnection *conn);

    // called to force the transaction queue to be processed once more, giving
    // preference to the specified connection.
    nsresult ProcessPendingQ(nsHttpConnectionInfo *);
    bool     ProcessPendingQForEntry(nsHttpConnectionInfo *);

    // Try and process all pending transactions
    nsresult ProcessPendingQ();

    // This is used to force an idle connection to be closed and removed from
    // the idle connection list. It is called when the idle connection detects
    // that the network peer has closed the transport.
    nsresult CloseIdleConnection(nsHttpConnection *);

    // The connection manager needs to know when a normal HTTP connection has been
    // upgraded to SPDY because the dispatch and idle semantics are a little
    // bit different.
    void ReportSpdyConnection(nsHttpConnection *, bool usingSpdy);

    bool     SupportsPipelining(nsHttpConnectionInfo *);

    bool GetConnectionData(nsTArray<HttpRetParams> *);

    void ResetIPFamilyPreference(nsHttpConnectionInfo *);

    uint16_t MaxRequestDelay() { return mMaxRequestDelay; }

    // public, so that the SPDY/http2 seesions can activate
    void ActivateTimeoutTick();

private:
    virtual ~nsHttpConnectionMgr();

    enum PipeliningState {
        // Host has proven itself pipeline capable through past experience and
        // large pipeline depths are allowed on multiple connections.
        PS_GREEN,

        // Not enough information is available yet with this host to be certain
        // of pipeline capability. Small pipelines on a single connection are
        // allowed in order to decide whether or not to proceed to green.
        PS_YELLOW,

        // One or more bad events has happened that indicate that pipelining
        // to this host (or a particular type of transaction with this host)
        // is a bad idea. Pipelining is not currently allowed, but time and
        // other positive experiences will eventually allow it to try again.
        PS_RED
    };

    class nsHalfOpenSocket;

    // nsConnectionEntry
    //
    // mCT maps connection info hash key to nsConnectionEntry object, which
    // contains list of active and idle connections as well as the list of
    // pending transactions.
    //
    class nsConnectionEntry
    {
    public:
        explicit nsConnectionEntry(nsHttpConnectionInfo *ci);
        ~nsConnectionEntry();

        RefPtr<nsHttpConnectionInfo> mConnInfo;
        nsTArray<RefPtr<nsHttpTransaction> > mPendingQ;    // pending transaction queue
        nsTArray<RefPtr<nsHttpConnection> >  mActiveConns; // active connections
        nsTArray<RefPtr<nsHttpConnection> >  mIdleConns;   // idle persistent connections
        nsTArray<nsHalfOpenSocket*>  mHalfOpens;   // half open connections

        bool AvailableForDispatchNow();

        // calculate the number of half open sockets that have not had at least 1
        // connection complete
        uint32_t UnconnectedHalfOpens();

        // Remove a particular half open socket from the mHalfOpens array
        void RemoveHalfOpen(nsHalfOpenSocket *);

        // Pipeline depths for various states
        const static uint32_t kPipelineUnlimited  = 1024; // fully open - extended green
        const static uint32_t kPipelineOpen       = 6;    // 6 on each conn - normal green
        const static uint32_t kPipelineRestricted = 2;    // 2 on just 1 conn in yellow

        nsHttpConnectionMgr::PipeliningState PipelineState();
        void OnPipelineFeedbackInfo(
            nsHttpConnectionMgr::PipelineFeedbackInfoType info,
            nsHttpConnection *, uint32_t);
        bool SupportsPipelining();
        uint32_t MaxPipelineDepth(nsAHttpTransaction::Classifier classification);
        void CreditPenalty();

        nsHttpConnectionMgr::PipeliningState mPipelineState;

        void SetYellowConnection(nsHttpConnection *);
        void OnYellowComplete();
        uint32_t                  mYellowGoodEvents;
        uint32_t                  mYellowBadEvents;
        nsHttpConnection         *mYellowConnection;

        // initialGreenDepth is the max depth of a pipeline when you first
        // transition to green. Normally this is kPipelineOpen, but it can
        // be kPipelineUnlimited in aggressive mode.
        uint32_t                  mInitialGreenDepth;

        // greenDepth is the current max allowed depth of a pipeline when
        // in the green state. Normally this starts as kPipelineOpen and
        // grows to kPipelineUnlimited after a pipeline of depth 3 has been
        // successfully transacted.
        uint32_t                  mGreenDepth;

        // pipeliningPenalty is the current amount of penalty points this host
        // entry has earned for participating in events that are not conducive
        // to good pipelines - such as head of line blocking, canceled pipelines,
        // etc.. penalties are paid back either through elapsed time or simply
        // healthy transactions. Having penalty points means that this host is
        // not currently eligible for pipelines.
        int16_t                   mPipeliningPenalty;

        // some penalty points only apply to particular classifications of
        // transactions - this allows a server that perhaps has head of line
        // blocking problems on CGI queries to still serve JS pipelined.
        int16_t                   mPipeliningClassPenalty[nsAHttpTransaction::CLASS_MAX];

        // for calculating penalty repair credits
        TimeStamp        mLastCreditTime;

        // Spdy sometimes resolves the address in the socket manager in order
        // to re-coalesce sharded HTTP hosts. The dotted decimal address is
        // combined with the Anonymous flag from the connection information
        // to build the hash key for hosts in the same ip pool.
        //
        // When a set of hosts are coalesced together one of them is marked
        // mSpdyPreferred. The mapping is maintained in the connection mananger
        // mSpdyPreferred hash.
        //
        nsTArray<nsCString> mCoalescingKeys;

        // To have the UsingSpdy flag means some host with the same connection
        // entry has done NPN=spdy/* at some point. It does not mean every
        // connection is currently using spdy.
        bool mUsingSpdy : 1;

        bool mInPreferredHash : 1;

        // Flags to remember our happy-eyeballs decision.
        // Reset only by Ctrl-F5 reload.
        // True when we've first connected an IPv4 server for this host,
        // initially false.
        bool mPreferIPv4 : 1;
        // True when we've first connected an IPv6 server for this host,
        // initially false.
        bool mPreferIPv6 : 1;

        // True if this connection entry has initiated a socket
        bool mUsedForConnection : 1;

        // Set the IP family preference flags according the connected family
        void RecordIPFamilyPreference(uint16_t family);
        // Resets all flags to their default values
        void ResetIPFamilyPreference();
    };

public:
    static nsAHttpConnection *MakeConnectionHandle(nsHttpConnection *aWrapped);

private:

    // nsHalfOpenSocket is used to hold the state of an opening TCP socket
    // while we wait for it to establish and bind it to a connection

    class nsHalfOpenSocket final : public nsIOutputStreamCallback,
                                   public nsITransportEventSink,
                                   public nsIInterfaceRequestor,
                                   public nsITimerCallback
    {
        ~nsHalfOpenSocket();

    public:
        NS_DECL_THREADSAFE_ISUPPORTS
        NS_DECL_NSIOUTPUTSTREAMCALLBACK
        NS_DECL_NSITRANSPORTEVENTSINK
        NS_DECL_NSIINTERFACEREQUESTOR
        NS_DECL_NSITIMERCALLBACK

        nsHalfOpenSocket(nsConnectionEntry *ent,
                         nsAHttpTransaction *trans,
                         uint32_t caps);

        nsresult SetupStreams(nsISocketTransport **,
                              nsIAsyncInputStream **,
                              nsIAsyncOutputStream **,
                              bool isBackup);
        nsresult SetupPrimaryStreams();
        nsresult SetupBackupStreams();
        void     SetupBackupTimer();
        void     CancelBackupTimer();
        void     Abandon();
        double   Duration(TimeStamp epoch);
        nsISocketTransport *SocketTransport() { return mSocketTransport; }
        nsISocketTransport *BackupTransport() { return mBackupTransport; }

        nsAHttpTransaction *Transaction() { return mTransaction; }

        bool IsSpeculative() { return mSpeculative; }
        void SetSpeculative(bool val) { mSpeculative = val; }

        bool IsFromPredictor() { return mIsFromPredictor; }
        void SetIsFromPredictor(bool val) { mIsFromPredictor = val; }

        bool Allow1918() { return mAllow1918; }
        void SetAllow1918(bool val) { mAllow1918 = val; }

        bool HasConnected() { return mHasConnected; }

        void PrintDiagnostics(nsCString &log);
    private:
        nsConnectionEntry              *mEnt;
        RefPtr<nsAHttpTransaction>   mTransaction;
        bool                           mDispatchedMTransaction;
        nsCOMPtr<nsISocketTransport>   mSocketTransport;
        nsCOMPtr<nsIAsyncOutputStream> mStreamOut;
        nsCOMPtr<nsIAsyncInputStream>  mStreamIn;
        uint32_t                       mCaps;

        // mSpeculative is set if the socket was created from
        // SpeculativeConnect(). It is cleared when a transaction would normally
        // start a new connection from scratch but instead finds this one in
        // the half open list and claims it for its own use. (which due to
        // the vagaries of scheduling from the pending queue might not actually
        // match up - but it prevents a speculative connection from opening
        // more connections that are needed.)
        bool                           mSpeculative;

        // mIsFromPredictor is set if the socket originated from the network
        // Predictor. It is used to gather telemetry data on used speculative
        // connections from the predictor.
        bool                           mIsFromPredictor;

        bool                           mAllow1918;

        TimeStamp             mPrimarySynStarted;
        TimeStamp             mBackupSynStarted;

        // for syn retry
        nsCOMPtr<nsITimer>             mSynTimer;
        nsCOMPtr<nsISocketTransport>   mBackupTransport;
        nsCOMPtr<nsIAsyncOutputStream> mBackupStreamOut;
        nsCOMPtr<nsIAsyncInputStream>  mBackupStreamIn;

        // mHasConnected tracks whether one of the sockets has completed the
        // connection process. It may have completed unsuccessfully.
        bool                           mHasConnected;

        bool                           mPrimaryConnectedOK;
        bool                           mBackupConnectedOK;
    };
    friend class nsHalfOpenSocket;

    //-------------------------------------------------------------------------
    // NOTE: these members may be accessed from any thread (use mReentrantMonitor)
    //-------------------------------------------------------------------------

    ReentrantMonitor    mReentrantMonitor;
    nsCOMPtr<nsIEventTarget>     mSocketThreadTarget;

    // connection limits
    uint16_t mMaxConns;
    uint16_t mMaxPersistConnsPerHost;
    uint16_t mMaxPersistConnsPerProxy;
    uint16_t mMaxRequestDelay; // in seconds
    uint16_t mMaxPipelinedRequests;
    uint16_t mMaxOptimisticPipelinedRequests;
    Atomic<bool, mozilla::Relaxed> mIsShuttingDown;

    //-------------------------------------------------------------------------
    // NOTE: these members are only accessed on the socket transport thread
    //-------------------------------------------------------------------------

    bool     ProcessPendingQForEntry(nsConnectionEntry *, bool considerAll);
    bool     IsUnderPressure(nsConnectionEntry *ent,
                             nsHttpTransaction::Classifier classification);
    bool     AtActiveConnectionLimit(nsConnectionEntry *, uint32_t caps);
    nsresult TryDispatchTransaction(nsConnectionEntry *ent,
                                    bool onlyReusedConnection,
                                    nsHttpTransaction *trans);
    nsresult DispatchTransaction(nsConnectionEntry *,
                                 nsHttpTransaction *,
                                 nsHttpConnection *);
    nsresult DispatchAbstractTransaction(nsConnectionEntry *,
                                         nsAHttpTransaction *,
                                         uint32_t,
                                         nsHttpConnection *,
                                         int32_t);
    nsresult BuildPipeline(nsConnectionEntry *,
                           nsAHttpTransaction *,
                           nsHttpPipeline **);
    bool     RestrictConnections(nsConnectionEntry *);
    nsresult ProcessNewTransaction(nsHttpTransaction *);
    nsresult EnsureSocketThreadTarget();
    void     ClosePersistentConnections(nsConnectionEntry *ent);
    nsresult CreateTransport(nsConnectionEntry *, nsAHttpTransaction *,
                             uint32_t, bool, bool, bool);
    void     AddActiveConn(nsHttpConnection *, nsConnectionEntry *);
    void     DecrementActiveConnCount(nsHttpConnection *);
    void     StartedConnect();
    void     RecvdConnect();

    nsConnectionEntry *GetOrCreateConnectionEntry(nsHttpConnectionInfo *,
                                                  bool allowWildCard);

    nsresult MakeNewConnection(nsConnectionEntry *ent,
                               nsHttpTransaction *trans);
    bool     AddToShortestPipeline(nsConnectionEntry *ent,
                                   nsHttpTransaction *trans,
                                   nsHttpTransaction::Classifier classification,
                                   uint16_t depthLimit);

    // Manage the preferred spdy connection entry for this address
    nsConnectionEntry *GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry);
    nsConnectionEntry *LookupPreferredHash(nsConnectionEntry *ent);
    void               StorePreferredHash(nsConnectionEntry *ent);
    void               RemovePreferredHash(nsConnectionEntry *ent);
    nsHttpConnection  *GetSpdyPreferredConn(nsConnectionEntry *ent);
    nsDataHashtable<nsCStringHashKey, nsConnectionEntry *>   mSpdyPreferredHash;
    nsConnectionEntry *LookupConnectionEntry(nsHttpConnectionInfo *ci,
                                             nsHttpConnection *conn,
                                             nsHttpTransaction *trans);

    void               ProcessSpdyPendingQ(nsConnectionEntry *ent);

    // used to marshall events to the socket transport thread.
    nsresult PostEvent(nsConnEventHandler  handler,
                       int32_t             iparam = 0,
                       ARefBase            *vparam = nullptr);

    // message handlers
    void OnMsgShutdown             (int32_t, ARefBase *);
    void OnMsgShutdownConfirm      (int32_t, ARefBase *);
    void OnMsgNewTransaction       (int32_t, ARefBase *);
    void OnMsgReschedTransaction   (int32_t, ARefBase *);
    void OnMsgCancelTransaction    (int32_t, ARefBase *);
    void OnMsgCancelTransactions   (int32_t, ARefBase *);
    void OnMsgProcessPendingQ      (int32_t, ARefBase *);
    void OnMsgPruneDeadConnections (int32_t, ARefBase *);
    void OnMsgSpeculativeConnect   (int32_t, ARefBase *);
    void OnMsgReclaimConnection    (int32_t, ARefBase *);
    void OnMsgCompleteUpgrade      (int32_t, ARefBase *);
    void OnMsgUpdateParam          (int32_t, ARefBase *);
    void OnMsgDoShiftReloadConnectionCleanup (int32_t, ARefBase *);
    void OnMsgProcessFeedback      (int32_t, ARefBase *);
    void OnMsgProcessAllSpdyPendingQ (int32_t, ARefBase *);
    void OnMsgUpdateRequestTokenBucket (int32_t, ARefBase *);
    void OnMsgVerifyTraffic (int32_t, ARefBase *);
    void OnMsgPruneNoTraffic (int32_t, ARefBase *);

    // Total number of active connections in all of the ConnectionEntry objects
    // that are accessed from mCT connection table.
    uint16_t mNumActiveConns;
    // Total number of idle connections in all of the ConnectionEntry objects
    // that are accessed from mCT connection table.
    uint16_t mNumIdleConns;
    // Total number of spdy connections which are a subset of the active conns
    uint16_t mNumSpdyActiveConns;
    // Total number of connections in mHalfOpens ConnectionEntry objects
    // that are accessed from mCT connection table
    uint32_t mNumHalfOpenConns;

    // Holds time in seconds for next wake-up to prune dead connections.
    uint64_t mTimeOfNextWakeUp;
    // Timer for next pruning of dead connections.
    nsCOMPtr<nsITimer> mTimer;
    // Timer for pruning stalled connections after changed network.
    nsCOMPtr<nsITimer> mTrafficTimer;
    bool mPruningNoTraffic;

    // A 1s tick to call nsHttpConnection::ReadTimeoutTick on
    // active http/1 connections and check for orphaned half opens.
    // Disabled when there are no active or half open connections.
    nsCOMPtr<nsITimer> mTimeoutTick;
    bool mTimeoutTickArmed;
    uint32_t mTimeoutTickNext;

    //
    // the connection table
    //
    // this table is indexed by connection key.  each entry is a
    // nsConnectionEntry object. It is unlocked and therefore must only
    // be accessed from the socket thread.
    //
    nsClassHashtable<nsCStringHashKey, nsConnectionEntry> mCT;

    // Read Timeout Tick handlers
    void TimeoutTick();

    // For diagnostics
    void OnMsgPrintDiagnostics(int32_t, ARefBase *);

    nsCString mLogData;
};

} // namespace net
} // namespace mozilla

#endif // !nsHttpConnectionMgr_h__