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__