Source code

Revision control

Copy as Markdown

Other Tools

/* 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);
// The connection manager needs to know the hashes used for a WebTransport
// connection authenticated with serverCertHashes
nsresult StoreServerCertHashes(
nsHttpConnectionInfo* aConnInfo, bool aNoSpdy, bool aNoHttp3,
nsTArray<RefPtr<nsIWebTransportHash>>&& aServerCertHashes);
//-------------------------------------------------------------------------
// 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();
const nsTArray<RefPtr<nsIWebTransportHash>>* GetServerCertHashes(
nsHttpConnectionInfo* aConnInfo);
uint64_t GenerateNewWebTransportId() { return mMaxWebTransportId++; }
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*);
void OnMsgStoreServerCertHashes(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);
// Used for generating unique IDSs for dedicated connections, currently used
// by WebTransport
Atomic<uint64_t> mMaxWebTransportId{1};
};
} // namespace mozilla::net
#endif // !nsHttpConnectionMgr_h__