Files
sousa-gecko/netwerk/protocol/http/ConnectionAttemptPool.cpp
T
Emilio Cobos Álvarez abbeff4fd9 Bug 2054311 - Sort headers in netwerk/. r=webrtc-reviewers,cookie-reviewers,mjf,timhuang
Autogenerated with:

    cp dom/.clang-format netwerk/ && mach format netwerk/**.{cpp,h,mm}

Manual fixes:

 * mozurl/cbindgen.toml (including headers earlier)
 * NetlinkService.h (forward-declaring a necessary struct)
 * nsIWebSocketChannel.idl (forward-declaring OriginAttributes).
 * nsAsyncRedirectVerifyHelper.h (forward-declaring nsIEventTarget)
 * CapsuleEncoder.h gets a missing Capsule forward-decl.
 * WebSocketConnectionBase.h gets some missing includes.
 * HappyEyeballsConnectionAttempt gets some missing includes.
 * nsUDPSocket missed nsSocketTransportService2.h for OnSocketThread().
 * HttpInfo missed a forward declaration.
 * MockHttpAuth missed an nsCOMPtr include.
 * nsHttpAuthManager missed a forward declaration for nsIHttpAuthCache.
 * WebTransportSessionProxy was using mozilla::Mutex in a member without
   including it.
 * win32 fixes to keep include order because windows headers suck.
 * nsInputStreamPump needs an Atomics.h include.

Differential Revision: https://phabricator.services.mozilla.com/D311696
2026-07-13 09:55:57 +00:00

227 lines
6.9 KiB
C++

/* 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/. */
// HttpLog.h should generally be included first
#include "HttpLog.h"
// Log on level :5, instead of default :4.
#undef LOG
#define LOG(args) LOG5(args)
#undef LOG_ENABLED
#define LOG_ENABLED() LOG5_ENABLED()
#include "ConnectionAttemptPool.h"
#include "ConnectionEntry.h"
#include "DnsAndConnectSocket.h"
#include "HappyEyeballsConnectionAttempt.h"
#include "nsHttpConnectionMgr.h"
#include "nsHttpHandler.h"
namespace mozilla::net {
ConnectionAttemptPool::ConnectionAttemptPool(ConnectionEntry* aEntry)
: mEntry(aEntry) {
LOG(("ConnectionAttemptPool ctor %p", this));
}
ConnectionAttemptPool::~ConnectionAttemptPool() {
LOG(("ConnectionAttemptPool dtor %p", this));
MOZ_DIAGNOSTIC_ASSERT(mAttempts.IsEmpty());
}
nsresult ConnectionAttemptPool::StartConnectionEstablishment(
ConnectionEntry* entry, nsAHttpTransaction* trans, uint32_t caps,
bool speculative, bool urgentStart, bool allow1918,
PendingTransactionInfo* pendingTransInfo, bool retryWithoutTRR) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
MOZ_ASSERT((speculative && !pendingTransInfo) ||
(!speculative && pendingTransInfo));
RefPtr<ConnectionAttempt> connAttempt;
nsHttpConnectionInfo* ci = trans->ConnectionInfo();
if (ci->GetHappyEyeballsEnabled()) {
connAttempt = new HappyEyeballsConnectionAttempt(
ci, trans, caps, speculative, urgentStart, retryWithoutTRR);
} else {
connAttempt = new DnsAndConnectSocket(entry->mConnInfo, trans, caps,
speculative, urgentStart);
}
if (speculative) {
connAttempt->SetAllow1918(allow1918);
}
nsresult rv = connAttempt->Init(entry);
if (NS_FAILED(rv)) {
connAttempt->Abandon();
return rv;
}
InsertIntoConnectionAttempts(connAttempt);
if (pendingTransInfo) {
bool claimed = connAttempt->Claim();
if (!claimed) {
// We should always be able to claim this.
MOZ_ASSERT(false, "Failed to claim a connAttempt");
return NS_ERROR_UNEXPECTED;
}
pendingTransInfo->RememberConnectionAttempt(connAttempt);
}
return NS_OK;
}
void ConnectionAttemptPool::InsertIntoConnectionAttempts(
ConnectionAttempt* sock) {
mAttempts.AppendElement(sock);
++mUnconnectedCount;
gHttpHandler->ConnMgr()->IncreaseNumDnsAndConnectSockets();
}
void ConnectionAttemptPool::RemoveConnectionAttempt(ConnectionAttempt* sock,
bool abandon) {
RefPtr<ConnectionAttempt> keepAlive(sock);
if (abandon) {
sock->Abandon();
}
if (mAttempts.RemoveElement(sock)) {
if (!sock->HasConnected()) {
MOZ_ASSERT(mUnconnectedCount > 0);
--mUnconnectedCount;
}
gHttpHandler->ConnMgr()->DecreaseNumDnsAndConnectSockets();
}
if (!UnconnectedConnectionAttempts()) {
// perhaps this reverted RestrictConnections()
// use the PostEvent version of processpendingq to avoid
// altering the pending q vector from an arbitrary stack
RefPtr<ConnectionEntry> entry(mEntry);
if (entry) {
gHttpHandler->ConnMgr()->ProcessPendingQForEntry(entry);
}
}
}
uint32_t ConnectionAttemptPool::UnconnectedConnectionAttempts() const {
#ifdef DEBUG
uint32_t computed = 0;
for (uint32_t i = 0; i < mAttempts.Length(); ++i) {
if (!mAttempts[i]->HasConnected()) {
++computed;
}
}
MOZ_ASSERT(mUnconnectedCount == computed);
#endif
return mUnconnectedCount;
}
void ConnectionAttemptPool::OnConnectionAttemptConnected() {
MOZ_ASSERT(mUnconnectedCount > 0);
--mUnconnectedCount;
}
void ConnectionAttemptPool::CloseAllConnectionAttempts() {
for (const auto& sock : mAttempts) {
sock->Abandon();
gHttpHandler->ConnMgr()->DecreaseNumDnsAndConnectSockets();
}
mAttempts.Clear();
mUnconnectedCount = 0;
RefPtr<ConnectionEntry> entry(mEntry);
if (entry) {
gHttpHandler->ConnMgr()->ProcessPendingQForEntry(entry);
}
}
bool ConnectionAttemptPool::FindConnToClaim(
PendingTransactionInfo* pendingTransInfo) {
nsHttpTransaction* trans = pendingTransInfo->Transaction();
for (const auto& sock : mAttempts) {
if (sock->AcceptsTransaction(trans) && sock->Claim(trans)) {
pendingTransInfo->RememberConnectionAttempt(sock);
// We've found a speculative connection or a connection that
// is free to be used in the mAttempts list.
// A free to be used connection is a connection that was
// open for a concrete transaction, but that trunsaction
// ended up using another connection.
LOG(
("ConnectionAttemptPool::FindConnToClaim [ci = %s]\n"
"Found a speculative or a free-to-use ConnectionAttempt\n",
trans->ConnectionInfo()->HashKey().get()));
// return OK because we have essentially opened a new connection
// by converting a speculative connection to general use
return true;
}
}
return false;
}
void ConnectionAttemptPool::TimeoutTick() {
if (mAttempts.IsEmpty()) {
return;
}
TimeStamp currentTime = TimeStamp::Now();
double maxConnectTime_ms = gHttpHandler->ConnectTimeout();
// Iterate a snapshot: OnTimeout / RemoveConnectionAttempt below can
// mutate mAttempts (directly or via reentrant Close paths), which
// would invalidate iterators over the live array.
nsTArray<RefPtr<ConnectionAttempt>> snapshot(mAttempts.Clone());
for (const auto& sock : snapshot) {
double delta = sock->Duration(currentTime);
// If the socket has timed out, close it so the waiting
// transaction will get the proper signal.
if (delta > maxConnectTime_ms) {
LOG(("Force timeout of ConnectionAttempt to %p after %.2fms.\n",
sock.get(), delta));
sock->OnTimeout();
}
// If this ConnectionAttempt hangs around for 5 seconds after we've
// closed() it then just abandon the socket.
if (delta > maxConnectTime_ms + 5000) {
LOG(("Abandon ConnectionAttempt to %p after %.2fms.\n", sock.get(),
delta));
RemoveConnectionAttempt(sock, true);
}
}
}
void ConnectionAttemptPool::PrintDiagnostics(nsCString& log) {
if (mAttempts.IsEmpty()) {
return;
}
uint32_t count = 0;
for (const auto& sock : Reversed(mAttempts)) {
log.AppendPrintf(" :: Half Open #%u\n", count);
sock->PrintDiagnostics(log);
count++;
}
}
void ConnectionAttemptPool::GetConnectionData(HttpRetParams& data) {
for (uint32_t i = 0; i < mAttempts.Length(); i++) {
DnsAndConnectSockets dnsAndSock{};
dnsAndSock.speculative = mAttempts[i]->IsSpeculative();
data.dnsAndSocks.AppendElement(dnsAndSock);
}
}
uint32_t ConnectionAttemptPool::UnconnectedUDPConnsLength() const {
uint32_t len = 0;
for (const auto& sock : mAttempts) {
len += sock->UnconnectedUDPConnsLength();
}
return len;
}
} // namespace mozilla::net