tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsHttpConnectionMgr.h (20852B)


      1 /* vim:t ts=4 sw=2 sts=2 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 #ifndef nsHttpConnectionMgr_h__
      7 #define nsHttpConnectionMgr_h__
      8 
      9 #include "DnsAndConnectSocket.h"
     10 #include "HttpConnectionBase.h"
     11 #include "HttpConnectionMgrShell.h"
     12 #include "nsHttpConnection.h"
     13 #include "nsHttpTransaction.h"
     14 #include "nsTArray.h"
     15 #include "nsThreadUtils.h"
     16 #include "nsClassHashtable.h"
     17 #include "mozilla/ReentrantMonitor.h"
     18 #include "mozilla/TimeStamp.h"
     19 #include "ARefBase.h"
     20 #include "nsWeakReference.h"
     21 #include "ConnectionEntry.h"
     22 
     23 #include "nsINamed.h"
     24 #include "nsIObserver.h"
     25 #include "nsITimer.h"
     26 
     27 class nsIHttpUpgradeListener;
     28 
     29 namespace mozilla::net {
     30 class EventTokenBucket;
     31 class NullHttpTransaction;
     32 struct HttpRetParams;
     33 struct Http3ConnectionStatsParams;
     34 
     35 //-----------------------------------------------------------------------------
     36 
     37 // message handlers have this signature
     38 class nsHttpConnectionMgr;
     39 using nsConnEventHandler = void (nsHttpConnectionMgr::*)(int32_t, ARefBase*);
     40 
     41 class nsHttpConnectionMgr final : public HttpConnectionMgrShell,
     42                                  public nsIObserver,
     43                                  nsINamed {
     44 public:
     45  NS_DECL_THREADSAFE_ISUPPORTS
     46  NS_DECL_HTTPCONNECTIONMGRSHELL
     47  NS_DECL_NSIOBSERVER
     48  NS_DECL_NSINAMED
     49 
     50  //-------------------------------------------------------------------------
     51  // NOTE: functions below may only be called on the main thread.
     52  //-------------------------------------------------------------------------
     53 
     54  nsHttpConnectionMgr();
     55 
     56  //-------------------------------------------------------------------------
     57  // NOTE: functions below may be called on any thread.
     58  //-------------------------------------------------------------------------
     59 
     60  [[nodiscard]] nsresult CancelTransactions(nsHttpConnectionInfo*,
     61                                            nsresult code);
     62 
     63  // The connection manager needs to know the hashes used for a WebTransport
     64  // connection authenticated with serverCertHashes
     65  nsresult StoreServerCertHashes(
     66      nsHttpConnectionInfo* aConnInfo, bool aNoSpdy, bool aNoHttp3,
     67      nsTArray<RefPtr<nsIWebTransportHash>>&& aServerCertHashes);
     68 
     69  //-------------------------------------------------------------------------
     70  // NOTE: functions below may be called only on the socket thread.
     71  //-------------------------------------------------------------------------
     72 
     73  // called to change the connection entry associated with conn from specific
     74  // into a wildcard (i.e. http2 proxy friendy) mapping
     75  void MoveToWildCardConnEntry(nsHttpConnectionInfo* specificCI,
     76                               nsHttpConnectionInfo* wildcardCI,
     77                               HttpConnectionBase* conn);
     78 
     79  // Remove a transaction from the pendingQ of it's connection entry. Returns
     80  // true if the transaction is removed successfully, otherwise returns false.
     81  bool RemoveTransFromConnEntry(nsHttpTransaction* aTrans,
     82                                const nsACString& aHashKey);
     83 
     84  // Directly dispatch the transaction or insert it in to the pendingQ.
     85  [[nodiscard]] nsresult ProcessNewTransaction(nsHttpTransaction* aTrans);
     86 
     87  // This is used to force an idle connection to be closed and removed from
     88  // the idle connection list. It is called when the idle connection detects
     89  // that the network peer has closed the transport.
     90  [[nodiscard]] nsresult CloseIdleConnection(nsHttpConnection*);
     91  [[nodiscard]] nsresult RemoveIdleConnection(nsHttpConnection*);
     92 
     93  // Close a single connection and prevent it from being reused.
     94  [[nodiscard]] nsresult DoSingleConnectionCleanup(nsHttpConnectionInfo*);
     95 
     96  // The connection manager needs to know when a normal HTTP connection has been
     97  // upgraded to SPDY because the dispatch and idle semantics are a little
     98  // bit different.
     99  void ReportSpdyConnection(nsHttpConnection*, bool usingSpdy,
    100                            bool disallowHttp3);
    101 
    102  void ReportHttp3Connection(HttpConnectionBase*);
    103 
    104  bool GetConnectionData(nsTArray<HttpRetParams>*);
    105  bool GetHttp3ConnectionStatsData(nsTArray<Http3ConnectionStatsParams>*);
    106 
    107  void ResetIPFamilyPreference(nsHttpConnectionInfo*);
    108 
    109  uint16_t MaxRequestDelay() { return mMaxRequestDelay; }
    110 
    111  // tracks and untracks active transactions according their throttle status
    112  void AddActiveTransaction(nsHttpTransaction* aTrans);
    113  void RemoveActiveTransaction(nsHttpTransaction* aTrans,
    114                               Maybe<bool> const& aOverride = Nothing());
    115  void UpdateActiveTransaction(nsHttpTransaction* aTrans);
    116 
    117  // called by nsHttpTransaction::WriteSegments.  decides whether the
    118  // transaction should limit reading its reponse data.  There are various
    119  // conditions this methods evaluates.  If called by an active-tab
    120  // non-throttled transaction, the throttling window time will be prolonged.
    121  bool ShouldThrottle(nsHttpTransaction* aTrans);
    122 
    123  // prolongs the throttling time window to now + the window preferred delay.
    124  // called when:
    125  // - any transaction is activated
    126  // - or when a currently unthrottled transaction for the active window
    127  // receives data
    128  void TouchThrottlingTimeWindow(bool aEnsureTicker = true);
    129 
    130  // return true iff the connection has pending transactions for the active tab.
    131  // it's mainly used to disallow throttling (limit reading) of a response
    132  // belonging to the same conn info to free up a connection ASAP.
    133  // NOTE: relatively expensive to call, there are two hashtable lookups.
    134  bool IsConnEntryUnderPressure(nsHttpConnectionInfo*);
    135 
    136  uint64_t CurrentBrowserId() { return mCurrentBrowserId; }
    137 
    138  void DoFallbackConnection(SpeculativeTransaction* aTrans, bool aFetchHTTPSRR);
    139  void DoSpeculativeConnection(SpeculativeTransaction* aTrans,
    140                               bool aFetchHTTPSRR);
    141 
    142  HttpConnectionBase* GetH2orH3ActiveConn(ConnectionEntry* ent, bool aNoHttp2,
    143                                          bool aNoHttp3);
    144 
    145  void IncreaseNumDnsAndConnectSockets();
    146  void DecreaseNumDnsAndConnectSockets();
    147 
    148  // Wen a new idle connection has been added, this function is called to
    149  // increment mNumIdleConns and update PruneDeadConnections timer.
    150  void NewIdleConnectionAdded(uint32_t timeToLive);
    151  void DecrementNumIdleConns();
    152 
    153  const nsTArray<RefPtr<nsIWebTransportHash>>* GetServerCertHashes(
    154      nsHttpConnectionInfo* aConnInfo);
    155 
    156 private:
    157  virtual ~nsHttpConnectionMgr();
    158 
    159  //-------------------------------------------------------------------------
    160  // NOTE: functions below may be called on any thread.
    161  //-------------------------------------------------------------------------
    162 
    163  // Schedules next pruning of dead connection to happen after
    164  // given time.
    165  void PruneDeadConnectionsAfter(uint32_t time);
    166 
    167  // Stops timer scheduled for next pruning of dead connections if
    168  // there are no more idle connections or active spdy ones
    169  void ConditionallyStopPruneDeadConnectionsTimer();
    170 
    171  // Stops timer used for the read timeout tick if there are no currently
    172  // active connections.
    173  void ConditionallyStopTimeoutTick();
    174 
    175  // called to close active connections with no registered "traffic"
    176  [[nodiscard]] nsresult PruneNoTraffic();
    177 
    178  //-------------------------------------------------------------------------
    179  // NOTE: functions below may be called only on the socket thread.
    180  //-------------------------------------------------------------------------
    181 
    182  [[nodiscard]] bool ProcessPendingQForEntry(nsHttpConnectionInfo*);
    183 
    184  // public, so that the SPDY/http2 seesions can activate
    185  void ActivateTimeoutTick();
    186 
    187  already_AddRefed<PendingTransactionInfo> FindTransactionHelper(
    188      bool removeWhenFound, ConnectionEntry* aEnt, nsAHttpTransaction* aTrans);
    189 
    190  void DoSpeculativeConnectionInternal(ConnectionEntry* aEnt,
    191                                       SpeculativeTransaction* aTrans,
    192                                       bool aFetchHTTPSRR);
    193 
    194  already_AddRefed<ConnectionEntry> FindConnectionEntry(
    195      const nsHttpConnectionInfo* ci);
    196 
    197 public:
    198  void RegisterOriginCoalescingKey(HttpConnectionBase*, const nsACString& host,
    199                                   int32_t port);
    200  // A test if be-conservative should be used when proxy is setup for the
    201  // connection
    202  bool BeConservativeIfProxied(nsIProxyInfo* proxy);
    203 
    204  bool AllowToRetryDifferentIPFamilyForHttp3(nsHttpConnectionInfo* ci,
    205                                             nsresult aError);
    206  void SetRetryDifferentIPFamilyForHttp3(nsHttpConnectionInfo* ci,
    207                                         uint16_t aIPFamily);
    208 
    209 protected:
    210  friend class ConnectionEntry;
    211  void IncrementActiveConnCount();
    212  void DecrementActiveConnCount(HttpConnectionBase*);
    213 
    214 private:
    215  friend class DnsAndConnectSocket;
    216  friend class PendingTransactionInfo;
    217 
    218  //-------------------------------------------------------------------------
    219  // NOTE: these members may be accessed from any thread (use mReentrantMonitor)
    220  //-------------------------------------------------------------------------
    221 
    222  ReentrantMonitor mReentrantMonitor{"nsHttpConnectionMgr.mReentrantMonitor"};
    223  // This is used as a flag that we're shut down, and no new events should be
    224  // dispatched.
    225  nsCOMPtr<nsIEventTarget> mSocketThreadTarget
    226      MOZ_GUARDED_BY(mReentrantMonitor);
    227 
    228  Atomic<bool, mozilla::Relaxed> mIsShuttingDown{false};
    229 
    230  //-------------------------------------------------------------------------
    231  // NOTE: these members are only accessed on the socket transport thread
    232  //-------------------------------------------------------------------------
    233  // connection limits
    234  uint16_t mMaxUrgentExcessiveConns{0};
    235  uint16_t mMaxConns{0};
    236  uint16_t mMaxPersistConnsPerHost{0};
    237  uint16_t mMaxPersistConnsPerProxy{0};
    238  uint16_t mMaxRequestDelay{0};  // in seconds
    239  bool mThrottleEnabled{false};
    240  uint32_t mThrottleSuspendFor{0};
    241  uint32_t mThrottleResumeFor{0};
    242  uint32_t mThrottleHoldTime{0};
    243  TimeDuration mThrottleMaxTime;
    244  bool mBeConservativeForProxy{true};
    245 
    246  [[nodiscard]] bool ProcessPendingQForEntry(ConnectionEntry*,
    247                                             bool considerAll);
    248  bool DispatchPendingQ(nsTArray<RefPtr<PendingTransactionInfo>>& pendingQ,
    249                        ConnectionEntry* ent, bool considerAll);
    250 
    251  // This function selects transactions from mPendingTransactionTable to
    252  // dispatch according to the following conditions:
    253  // 1. When network.http.active_tab_priority is false, only get transactions
    254  //    from the queue whose window id is 0.
    255  // 2. If |considerAll| is false, either get transactions from the focused
    256  //    window queue or non-focused ones.
    257  // 3. If |considerAll| is true, fill the |pendingQ| with the transactions from
    258  //    both focused window and non-focused window queues.
    259  void PreparePendingQForDispatching(
    260      ConnectionEntry* ent, nsTArray<RefPtr<PendingTransactionInfo>>& pendingQ,
    261      bool considerAll);
    262 
    263  // Return |mMaxPersistConnsPerProxy| or |mMaxPersistConnsPerHost|,
    264  // depending whether the proxy is used.
    265  uint32_t MaxPersistConnections(ConnectionEntry* ent) const;
    266 
    267  bool AtActiveConnectionLimit(ConnectionEntry*, uint32_t caps);
    268  [[nodiscard]] nsresult TryDispatchTransaction(
    269      ConnectionEntry* ent, bool onlyReusedConnection,
    270      PendingTransactionInfo* pendingTransInfo);
    271  [[nodiscard]] nsresult TryDispatchTransactionOnIdleConn(
    272      ConnectionEntry* ent, PendingTransactionInfo* pendingTransInfo,
    273      bool respectUrgency, bool* allUrgent = nullptr);
    274  [[nodiscard]] nsresult DispatchTransaction(ConnectionEntry*,
    275                                             nsHttpTransaction*,
    276                                             HttpConnectionBase*);
    277  [[nodiscard]] nsresult DispatchAbstractTransaction(ConnectionEntry*,
    278                                                     nsAHttpTransaction*,
    279                                                     uint32_t,
    280                                                     HttpConnectionBase*,
    281                                                     int32_t);
    282  [[nodiscard]] nsresult EnsureSocketThreadTarget();
    283  [[nodiscard]] nsresult TryDispatchExtendedCONNECTransaction(
    284      ConnectionEntry* aEnt, nsHttpTransaction* aTrans,
    285      nsHttpConnection* aConn);
    286  void StartedConnect();
    287  void RecvdConnect();
    288 
    289  ConnectionEntry* GetOrCreateConnectionEntry(
    290      nsHttpConnectionInfo*, bool prohibitWildCard, bool aNoHttp2,
    291      bool aNoHttp3, bool* aIsWildcard,
    292      bool* aAvailableForDispatchNow = nullptr);
    293 
    294  [[nodiscard]] nsresult MakeNewConnection(
    295      ConnectionEntry* ent, PendingTransactionInfo* pendingTransInfo);
    296 
    297  // Manage h2/3 connection coalescing
    298  // The hashtable contains arrays of weak pointers to HttpConnectionBases
    299  nsClassHashtable<nsCStringHashKey, nsTArray<nsWeakPtr>> mCoalescingHash;
    300 
    301  HttpConnectionBase* FindCoalescableConnection(ConnectionEntry* ent,
    302                                                bool justKidding, bool aNoHttp2,
    303                                                bool aNoHttp3);
    304  HttpConnectionBase* FindCoalescableConnectionByHashKey(ConnectionEntry* ent,
    305                                                         const nsCString& key,
    306                                                         bool justKidding,
    307                                                         bool aNoHttp2,
    308                                                         bool aNoHttp3);
    309  void UpdateCoalescingForNewConn(HttpConnectionBase* conn,
    310                                  ConnectionEntry* ent, bool aNoHttp3);
    311 
    312  void ProcessSpdyPendingQ(ConnectionEntry* ent);
    313  void DispatchSpdyPendingQ(nsTArray<RefPtr<PendingTransactionInfo>>& pendingQ,
    314                            ConnectionEntry* ent, HttpConnectionBase* connH2,
    315                            HttpConnectionBase* connH3);
    316  // used to marshall events to the socket transport thread.
    317  [[nodiscard]] nsresult PostEvent(nsConnEventHandler handler,
    318                                   int32_t iparam = 0,
    319                                   ARefBase* vparam = nullptr);
    320 
    321  void OnMsgReclaimConnection(HttpConnectionBase*);
    322 
    323  // message handlers
    324  void OnMsgShutdown(int32_t, ARefBase*);
    325  void OnMsgShutdownConfirm(int32_t, ARefBase*);
    326  void OnMsgNewTransaction(int32_t, ARefBase*);
    327  void OnMsgNewTransactionWithStickyConn(int32_t, ARefBase*);
    328  void OnMsgReschedTransaction(int32_t, ARefBase*);
    329  void OnMsgUpdateClassOfServiceOnTransaction(ClassOfService, ARefBase*);
    330  void OnMsgCancelTransaction(int32_t, ARefBase*);
    331  void OnMsgCancelTransactions(int32_t, ARefBase*);
    332  void OnMsgProcessPendingQ(int32_t, ARefBase*);
    333  void OnMsgPruneDeadConnections(int32_t, ARefBase*);
    334  void OnMsgSpeculativeConnect(int32_t, ARefBase*);
    335  void OnMsgCompleteUpgrade(int32_t, ARefBase*);
    336  void OnMsgUpdateParam(int32_t, ARefBase*);
    337  void OnMsgDoShiftReloadConnectionCleanup(int32_t, ARefBase*);
    338  void OnMsgDoSingleConnectionCleanup(int32_t, ARefBase*);
    339  void OnMsgProcessFeedback(int32_t, ARefBase*);
    340  void OnMsgProcessAllSpdyPendingQ(int32_t, ARefBase*);
    341  void OnMsgUpdateRequestTokenBucket(int32_t, ARefBase*);
    342  void OnMsgVerifyTraffic(int32_t, ARefBase*);
    343  void OnMsgPruneNoTraffic(int32_t, ARefBase*);
    344  void OnMsgUpdateCurrentBrowserId(int32_t, ARefBase*);
    345  void OnMsgClearConnectionHistory(int32_t, ARefBase*);
    346  void OnMsgStoreServerCertHashes(int32_t, ARefBase*);
    347 
    348  // Total number of active connections in all of the ConnectionEntry objects
    349  // that are accessed from mCT connection table.
    350  uint16_t mNumActiveConns{0};
    351  // Total number of idle connections in all of the ConnectionEntry objects
    352  // that are accessed from mCT connection table.
    353  uint16_t mNumIdleConns{0};
    354  // Total number of spdy or http3 connections which are a subset of the active
    355  // conns
    356  uint16_t mNumSpdyHttp3ActiveConns{0};
    357  // Total number of connections in DnsAndConnectSockets ConnectionEntry objects
    358  // that are accessed from mCT connection table
    359  uint32_t mNumDnsAndConnectSockets{0};
    360 
    361  // Holds time in seconds for next wake-up to prune dead connections.
    362  uint64_t mTimeOfNextWakeUp{UINT64_MAX};
    363  // Timer for next pruning of dead connections.
    364  nsCOMPtr<nsITimer> mTimer;
    365  // Timer for pruning stalled connections after changed network.
    366  nsCOMPtr<nsITimer> mTrafficTimer;
    367  bool mPruningNoTraffic{false};
    368 
    369  // A 1s tick to call nsHttpConnection::ReadTimeoutTick on
    370  // active http/1 connections and check for orphaned half opens.
    371  // Disabled when there are no active or half open connections.
    372  nsCOMPtr<nsITimer> mTimeoutTick;
    373  bool mTimeoutTickArmed{false};
    374  uint32_t mTimeoutTickNext{1};
    375 
    376  //
    377  // the connection table
    378  //
    379  // this table is indexed by connection key.  each entry is a
    380  // ConnectionEntry object. It is unlocked and therefore must only
    381  // be accessed from the socket thread.
    382  //
    383  nsRefPtrHashtable<nsCStringHashKey, ConnectionEntry> mCT;
    384 
    385  // Read Timeout Tick handlers
    386  void TimeoutTick();
    387 
    388  // For diagnostics
    389  void OnMsgPrintDiagnostics(int32_t, ARefBase*);
    390 
    391  nsCString mLogData;
    392  uint64_t mCurrentBrowserId{0};
    393 
    394  // Called on a pref change
    395  void SetThrottlingEnabled(bool aEnable);
    396 
    397  // we only want to throttle for a limited amount of time after a new
    398  // active transaction is added so that we don't block downloads on comet,
    399  // socket and any kind of longstanding requests that don't need bandwidth.
    400  // these methods track this time.
    401  bool InThrottlingTimeWindow();
    402 
    403  // Two hashtables keeping track of active transactions regarding window id and
    404  // throttling. Used by the throttling algorithm to obtain number of
    405  // transactions for the active tab and for inactive tabs according their
    406  // throttle status. mActiveTransactions[0] are all unthrottled transactions,
    407  // mActiveTransactions[1] throttled.
    408  nsClassHashtable<nsUint64HashKey, nsTArray<RefPtr<nsHttpTransaction>>>
    409      mActiveTransactions[2];
    410 
    411  // V1 specific
    412  // Whether we are inside the "stop reading" interval, altered by the throttle
    413  // ticker
    414  bool mThrottlingInhibitsReading{false};
    415 
    416  TimeStamp mThrottlingWindowEndsAt;
    417 
    418  // ticker for the 'stop reading'/'resume reading' signal
    419  nsCOMPtr<nsITimer> mThrottleTicker;
    420  // Checks if the combination of active transactions requires the ticker.
    421  bool IsThrottleTickerNeeded();
    422  // The method also unschedules the delayed resume of background tabs timer
    423  // if the ticker was about to be scheduled.
    424  void EnsureThrottleTickerIfNeeded();
    425  // V1:
    426  // Drops also the mThrottlingInhibitsReading flag.  Immediate or delayed
    427  // resume of currently throttled transactions is not affected by this method.
    428  // V2:
    429  // Immediate or delayed resume of currently throttled transactions is not
    430  // affected by this method.
    431  void DestroyThrottleTicker();
    432  // V1:
    433  // Handler for the ticker: alters the mThrottlingInhibitsReading flag.
    434  // V2:
    435  // Handler for the ticker: calls ResumeReading() for all throttled
    436  // transactions.
    437  void ThrottlerTick();
    438 
    439  // mechanism to delay immediate resume of background tabs and chrome initiated
    440  // throttled transactions after the last transaction blocking their unthrottle
    441  // has been removed.  Needs to be delayed because during a page load there is
    442  // a number of intervals when there is no transaction that would cause
    443  // throttling. Hence, throttling of long standing responses, like downloads,
    444  // would be mostly ineffective if resumed during every such interval.
    445  nsCOMPtr<nsITimer> mDelayedResumeReadTimer;
    446  // Schedule the resume
    447  void DelayedResumeBackgroundThrottledTransactions();
    448  // Simply destroys the timer
    449  void CancelDelayedResumeBackgroundThrottledTransactions();
    450  // Handler for the timer: resumes all background throttled transactions
    451  void ResumeBackgroundThrottledTransactions();
    452 
    453  // Simple helpers, iterates the given hash/array and resume.
    454  // @param excludeActive: skip active tabid transactions.
    455  void ResumeReadOf(
    456      nsClassHashtable<nsUint64HashKey, nsTArray<RefPtr<nsHttpTransaction>>>&,
    457      bool excludeForActiveTab = false);
    458  void ResumeReadOf(nsTArray<RefPtr<nsHttpTransaction>>*);
    459 
    460  // Cached status of the active tab active transactions existence,
    461  // saves a lot of hashtable lookups
    462  bool mActiveTabTransactionsExist{false};
    463  bool mActiveTabUnthrottledTransactionsExist{false};
    464 
    465  void LogActiveTransactions(char);
    466 
    467  // When current active tab is changed, this function uses
    468  // |previousId| to select background transactions and
    469  // |mCurrentBrowserId| to select foreground transactions.
    470  // Then, it notifies selected transactions' connection of the new active tab
    471  // id.
    472  void NotifyConnectionOfBrowserIdChange(uint64_t previousId);
    473 
    474  void CheckTransInPendingQueue(nsHttpTransaction* aTrans);
    475 };
    476 
    477 }  // namespace mozilla::net
    478 
    479 #endif  // !nsHttpConnectionMgr_h__