diff options
Diffstat (limited to '')
-rw-r--r-- | netwerk/protocol/http/nsHttpConnectionMgr.h | 469 |
1 files changed, 469 insertions, 0 deletions
diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.h b/netwerk/protocol/http/nsHttpConnectionMgr.h new file mode 100644 index 0000000000..2cf4ab7568 --- /dev/null +++ b/netwerk/protocol/http/nsHttpConnectionMgr.h @@ -0,0 +1,469 @@ +/* vim:t ts=4 sw=2 sts=2 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 "DnsAndConnectSocket.h" +#include "HttpConnectionBase.h" +#include "HttpConnectionMgrShell.h" +#include "nsHttpConnection.h" +#include "nsHttpTransaction.h" +#include "nsTArray.h" +#include "nsThreadUtils.h" +#include "nsClassHashtable.h" +#include "mozilla/ReentrantMonitor.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/Attributes.h" +#include "ARefBase.h" +#include "nsWeakReference.h" +#include "ConnectionEntry.h" + +#include "nsINamed.h" +#include "nsIObserver.h" +#include "nsITimer.h" + +class nsIHttpUpgradeListener; + +namespace mozilla::net { +class EventTokenBucket; +class NullHttpTransaction; +struct HttpRetParams; + +//----------------------------------------------------------------------------- + +// message handlers have this signature +class nsHttpConnectionMgr; +using nsConnEventHandler = void (nsHttpConnectionMgr::*)(int32_t, ARefBase*); + +class nsHttpConnectionMgr final : public HttpConnectionMgrShell, + public nsIObserver, + nsINamed { + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_HTTPCONNECTIONMGRSHELL + NS_DECL_NSIOBSERVER + NS_DECL_NSINAMED + + //------------------------------------------------------------------------- + // NOTE: functions below may only be called on the main thread. + //------------------------------------------------------------------------- + + nsHttpConnectionMgr(); + + //------------------------------------------------------------------------- + // NOTE: functions below may be called on any thread. + //------------------------------------------------------------------------- + + [[nodiscard]] nsresult CancelTransactions(nsHttpConnectionInfo*, + nsresult code); + + //------------------------------------------------------------------------- + // 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, + HttpConnectionBase* conn); + + // Remove a transaction from the pendingQ of it's connection entry. Returns + // true if the transaction is removed successfully, otherwise returns false. + bool RemoveTransFromConnEntry(nsHttpTransaction* aTrans, + const nsACString& aHashKey); + + // Directly dispatch the transaction or insert it in to the pendingQ. + [[nodiscard]] nsresult ProcessNewTransaction(nsHttpTransaction* aTrans); + + // 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. + [[nodiscard]] nsresult CloseIdleConnection(nsHttpConnection*); + [[nodiscard]] nsresult RemoveIdleConnection(nsHttpConnection*); + + // Close a single connection and prevent it from being reused. + [[nodiscard]] nsresult DoSingleConnectionCleanup(nsHttpConnectionInfo*); + + // 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 disallowHttp3); + + void ReportHttp3Connection(HttpConnectionBase*); + + bool GetConnectionData(nsTArray<HttpRetParams>*); + + void ResetIPFamilyPreference(nsHttpConnectionInfo*); + + uint16_t MaxRequestDelay() { return mMaxRequestDelay; } + + // tracks and untracks active transactions according their throttle status + void AddActiveTransaction(nsHttpTransaction* aTrans); + void RemoveActiveTransaction(nsHttpTransaction* aTrans, + Maybe<bool> const& aOverride = Nothing()); + void UpdateActiveTransaction(nsHttpTransaction* aTrans); + + // called by nsHttpTransaction::WriteSegments. decides whether the + // transaction should limit reading its reponse data. There are various + // conditions this methods evaluates. If called by an active-tab + // non-throttled transaction, the throttling window time will be prolonged. + bool ShouldThrottle(nsHttpTransaction* aTrans); + + // prolongs the throttling time window to now + the window preferred delay. + // called when: + // - any transaction is activated + // - or when a currently unthrottled transaction for the active window + // receives data + void TouchThrottlingTimeWindow(bool aEnsureTicker = true); + + // return true iff the connection has pending transactions for the active tab. + // it's mainly used to disallow throttling (limit reading) of a response + // belonging to the same conn info to free up a connection ASAP. + // NOTE: relatively expensive to call, there are two hashtable lookups. + bool IsConnEntryUnderPressure(nsHttpConnectionInfo*); + + uint64_t CurrentBrowserId() { return mCurrentBrowserId; } + + void DoFallbackConnection(SpeculativeTransaction* aTrans, bool aFetchHTTPSRR); + void DoSpeculativeConnection(SpeculativeTransaction* aTrans, + bool aFetchHTTPSRR); + + HttpConnectionBase* GetH2orH3ActiveConn(ConnectionEntry* ent, bool aNoHttp2, + bool aNoHttp3); + + void IncreaseNumDnsAndConnectSockets(); + void DecreaseNumDnsAndConnectSockets(); + + // Wen a new idle connection has been added, this function is called to + // increment mNumIdleConns and update PruneDeadConnections timer. + void NewIdleConnectionAdded(uint32_t timeToLive); + void DecrementNumIdleConns(); + + private: + virtual ~nsHttpConnectionMgr(); + + //------------------------------------------------------------------------- + // 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(); + + // called to close active connections with no registered "traffic" + [[nodiscard]] nsresult PruneNoTraffic(); + + //------------------------------------------------------------------------- + // NOTE: functions below may be called only on the socket thread. + //------------------------------------------------------------------------- + + [[nodiscard]] bool ProcessPendingQForEntry(nsHttpConnectionInfo*); + + // public, so that the SPDY/http2 seesions can activate + void ActivateTimeoutTick(); + + already_AddRefed<PendingTransactionInfo> FindTransactionHelper( + bool removeWhenFound, ConnectionEntry* aEnt, nsAHttpTransaction* aTrans); + + void DoSpeculativeConnectionInternal(ConnectionEntry* aEnt, + SpeculativeTransaction* aTrans, + bool aFetchHTTPSRR); + + already_AddRefed<ConnectionEntry> FindConnectionEntry( + const nsHttpConnectionInfo* ci); + + public: + void RegisterOriginCoalescingKey(HttpConnectionBase*, const nsACString& host, + int32_t port); + // A test if be-conservative should be used when proxy is setup for the + // connection + bool BeConservativeIfProxied(nsIProxyInfo* proxy); + + bool AllowToRetryDifferentIPFamilyForHttp3(nsHttpConnectionInfo* ci, + nsresult aError); + void SetRetryDifferentIPFamilyForHttp3(nsHttpConnectionInfo* ci, + uint16_t aIPFamily); + + protected: + friend class ConnectionEntry; + void IncrementActiveConnCount(); + void DecrementActiveConnCount(HttpConnectionBase*); + + private: + friend class DnsAndConnectSocket; + friend class PendingTransactionInfo; + + //------------------------------------------------------------------------- + // NOTE: these members may be accessed from any thread (use mReentrantMonitor) + //------------------------------------------------------------------------- + + ReentrantMonitor mReentrantMonitor{"nsHttpConnectionMgr.mReentrantMonitor"}; + // This is used as a flag that we're shut down, and no new events should be + // dispatched. + nsCOMPtr<nsIEventTarget> mSocketThreadTarget + MOZ_GUARDED_BY(mReentrantMonitor); + + Atomic<bool, mozilla::Relaxed> mIsShuttingDown{false}; + + //------------------------------------------------------------------------- + // NOTE: these members are only accessed on the socket transport thread + //------------------------------------------------------------------------- + // connection limits + uint16_t mMaxUrgentExcessiveConns{0}; + uint16_t mMaxConns{0}; + uint16_t mMaxPersistConnsPerHost{0}; + uint16_t mMaxPersistConnsPerProxy{0}; + uint16_t mMaxRequestDelay{0}; // in seconds + bool mThrottleEnabled{false}; + uint32_t mThrottleVersion{2}; + uint32_t mThrottleSuspendFor{0}; + uint32_t mThrottleResumeFor{0}; + uint32_t mThrottleReadLimit{0}; + uint32_t mThrottleReadInterval{0}; + uint32_t mThrottleHoldTime{0}; + TimeDuration mThrottleMaxTime; + bool mBeConservativeForProxy{true}; + + [[nodiscard]] bool ProcessPendingQForEntry(ConnectionEntry*, + bool considerAll); + bool DispatchPendingQ(nsTArray<RefPtr<PendingTransactionInfo>>& pendingQ, + ConnectionEntry* ent, bool considerAll); + + // This function selects transactions from mPendingTransactionTable to + // dispatch according to the following conditions: + // 1. When ActiveTabPriority() is false, only get transactions from the + // queue whose window id is 0. + // 2. If |considerAll| is false, either get transactions from the focused + // window queue or non-focused ones. + // 3. If |considerAll| is true, fill the |pendingQ| with the transactions from + // both focused window and non-focused window queues. + void PreparePendingQForDispatching( + ConnectionEntry* ent, nsTArray<RefPtr<PendingTransactionInfo>>& pendingQ, + bool considerAll); + + // Return |mMaxPersistConnsPerProxy| or |mMaxPersistConnsPerHost|, + // depending whether the proxy is used. + uint32_t MaxPersistConnections(ConnectionEntry* ent) const; + + bool AtActiveConnectionLimit(ConnectionEntry*, uint32_t caps); + [[nodiscard]] nsresult TryDispatchTransaction( + ConnectionEntry* ent, bool onlyReusedConnection, + PendingTransactionInfo* pendingTransInfo); + [[nodiscard]] nsresult TryDispatchTransactionOnIdleConn( + ConnectionEntry* ent, PendingTransactionInfo* pendingTransInfo, + bool respectUrgency, bool* allUrgent = nullptr); + [[nodiscard]] nsresult DispatchTransaction(ConnectionEntry*, + nsHttpTransaction*, + HttpConnectionBase*); + [[nodiscard]] nsresult DispatchAbstractTransaction(ConnectionEntry*, + nsAHttpTransaction*, + uint32_t, + HttpConnectionBase*, + int32_t); + [[nodiscard]] nsresult EnsureSocketThreadTarget(); + void ReportProxyTelemetry(ConnectionEntry* ent); + void StartedConnect(); + void RecvdConnect(); + + ConnectionEntry* GetOrCreateConnectionEntry( + nsHttpConnectionInfo*, bool prohibitWildCard, bool aNoHttp2, + bool aNoHttp3, bool* aIsWildcard, + bool* aAvailableForDispatchNow = nullptr); + + [[nodiscard]] nsresult MakeNewConnection( + ConnectionEntry* ent, PendingTransactionInfo* pendingTransInfo); + + // Manage h2/3 connection coalescing + // The hashtable contains arrays of weak pointers to HttpConnectionBases + nsClassHashtable<nsCStringHashKey, nsTArray<nsWeakPtr>> mCoalescingHash; + + HttpConnectionBase* FindCoalescableConnection(ConnectionEntry* ent, + bool justKidding, bool aNoHttp2, + bool aNoHttp3); + HttpConnectionBase* FindCoalescableConnectionByHashKey(ConnectionEntry* ent, + const nsCString& key, + bool justKidding, + bool aNoHttp2, + bool aNoHttp3); + void UpdateCoalescingForNewConn(HttpConnectionBase* conn, + ConnectionEntry* ent, bool aNoHttp3); + + void ProcessSpdyPendingQ(ConnectionEntry* ent); + void DispatchSpdyPendingQ(nsTArray<RefPtr<PendingTransactionInfo>>& pendingQ, + ConnectionEntry* ent, HttpConnectionBase* connH2, + HttpConnectionBase* connH3); + // used to marshall events to the socket transport thread. + [[nodiscard]] nsresult PostEvent(nsConnEventHandler handler, + int32_t iparam = 0, + ARefBase* vparam = nullptr); + + void OnMsgReclaimConnection(HttpConnectionBase*); + + // message handlers + void OnMsgShutdown(int32_t, ARefBase*); + void OnMsgShutdownConfirm(int32_t, ARefBase*); + void OnMsgNewTransaction(int32_t, ARefBase*); + void OnMsgNewTransactionWithStickyConn(int32_t, ARefBase*); + void OnMsgReschedTransaction(int32_t, ARefBase*); + void OnMsgUpdateClassOfServiceOnTransaction(ClassOfService, 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 OnMsgCompleteUpgrade(int32_t, ARefBase*); + void OnMsgUpdateParam(int32_t, ARefBase*); + void OnMsgDoShiftReloadConnectionCleanup(int32_t, ARefBase*); + void OnMsgDoSingleConnectionCleanup(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*); + void OnMsgUpdateCurrentBrowserId(int32_t, ARefBase*); + void OnMsgClearConnectionHistory(int32_t, ARefBase*); + + // Total number of active connections in all of the ConnectionEntry objects + // that are accessed from mCT connection table. + uint16_t mNumActiveConns{0}; + // Total number of idle connections in all of the ConnectionEntry objects + // that are accessed from mCT connection table. + uint16_t mNumIdleConns{0}; + // Total number of spdy or http3 connections which are a subset of the active + // conns + uint16_t mNumSpdyHttp3ActiveConns{0}; + // Total number of connections in DnsAndConnectSockets ConnectionEntry objects + // that are accessed from mCT connection table + uint32_t mNumDnsAndConnectSockets{0}; + + // Holds time in seconds for next wake-up to prune dead connections. + uint64_t mTimeOfNextWakeUp{UINT64_MAX}; + // Timer for next pruning of dead connections. + nsCOMPtr<nsITimer> mTimer; + // Timer for pruning stalled connections after changed network. + nsCOMPtr<nsITimer> mTrafficTimer; + bool mPruningNoTraffic{false}; + + // 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{false}; + uint32_t mTimeoutTickNext{1}; + + // + // the connection table + // + // this table is indexed by connection key. each entry is a + // ConnectionEntry object. It is unlocked and therefore must only + // be accessed from the socket thread. + // + nsRefPtrHashtable<nsCStringHashKey, ConnectionEntry> mCT; + + // Read Timeout Tick handlers + void TimeoutTick(); + + // For diagnostics + void OnMsgPrintDiagnostics(int32_t, ARefBase*); + + nsCString mLogData; + uint64_t mCurrentBrowserId{0}; + + // Called on a pref change + void SetThrottlingEnabled(bool aEnable); + + // we only want to throttle for a limited amount of time after a new + // active transaction is added so that we don't block downloads on comet, + // socket and any kind of longstanding requests that don't need bandwidth. + // these methods track this time. + bool InThrottlingTimeWindow(); + + // Two hashtalbes keeping track of active transactions regarding window id and + // throttling. Used by the throttling algorithm to obtain number of + // transactions for the active tab and for inactive tabs according their + // throttle status. mActiveTransactions[0] are all unthrottled transactions, + // mActiveTransactions[1] throttled. + nsClassHashtable<nsUint64HashKey, nsTArray<RefPtr<nsHttpTransaction>>> + mActiveTransactions[2]; + + // V1 specific + // Whether we are inside the "stop reading" interval, altered by the throttle + // ticker + bool mThrottlingInhibitsReading{false}; + + TimeStamp mThrottlingWindowEndsAt; + + // ticker for the 'stop reading'/'resume reading' signal + nsCOMPtr<nsITimer> mThrottleTicker; + // Checks if the combination of active transactions requires the ticker. + bool IsThrottleTickerNeeded(); + // The method also unschedules the delayed resume of background tabs timer + // if the ticker was about to be scheduled. + void EnsureThrottleTickerIfNeeded(); + // V1: + // Drops also the mThrottlingInhibitsReading flag. Immediate or delayed + // resume of currently throttled transactions is not affected by this method. + // V2: + // Immediate or delayed resume of currently throttled transactions is not + // affected by this method. + void DestroyThrottleTicker(); + // V1: + // Handler for the ticker: alters the mThrottlingInhibitsReading flag. + // V2: + // Handler for the ticker: calls ResumeReading() for all throttled + // transactions. + void ThrottlerTick(); + + // mechanism to delay immediate resume of background tabs and chrome initiated + // throttled transactions after the last transaction blocking their unthrottle + // has been removed. Needs to be delayed because during a page load there is + // a number of intervals when there is no transaction that would cause + // throttling. Hence, throttling of long standing responses, like downloads, + // would be mostly ineffective if resumed during every such interval. + nsCOMPtr<nsITimer> mDelayedResumeReadTimer; + // Schedule the resume + void DelayedResumeBackgroundThrottledTransactions(); + // Simply destroys the timer + void CancelDelayedResumeBackgroundThrottledTransactions(); + // Handler for the timer: resumes all background throttled transactions + void ResumeBackgroundThrottledTransactions(); + + // Simple helpers, iterates the given hash/array and resume. + // @param excludeActive: skip active tabid transactions. + void ResumeReadOf( + nsClassHashtable<nsUint64HashKey, nsTArray<RefPtr<nsHttpTransaction>>>&, + bool excludeForActiveTab = false); + void ResumeReadOf(nsTArray<RefPtr<nsHttpTransaction>>*); + + // Cached status of the active tab active transactions existence, + // saves a lot of hashtable lookups + bool mActiveTabTransactionsExist{false}; + bool mActiveTabUnthrottledTransactionsExist{false}; + + void LogActiveTransactions(char); + + // When current active tab is changed, this function uses + // |previousId| to select background transactions and + // |mCurrentBrowserId| to select foreground transactions. + // Then, it notifies selected transactions' connection of the new active tab + // id. + void NotifyConnectionOfBrowserIdChange(uint64_t previousId); + + void CheckTransInPendingQueue(nsHttpTransaction* aTrans); +}; + +} // namespace mozilla::net + +#endif // !nsHttpConnectionMgr_h__ |