mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1690615 - Move DNS lookup into DnsAndConnectSocket r=necko-reviewers,valentin
Differential Revision: https://phabricator.services.mozilla.com/D104464
This commit is contained in:
parent
169e0b5a38
commit
efa5705d23
@ -270,9 +270,9 @@ var _attemptTransport = async function(settings) {
|
||||
var _attemptConnect = async function({ host, port, encryption }) {
|
||||
let s;
|
||||
if (encryption) {
|
||||
s = socketTransportService.createTransport(["ssl"], host, port, null);
|
||||
s = socketTransportService.createTransport(["ssl"], host, port, null, null);
|
||||
} else {
|
||||
s = socketTransportService.createTransport([], host, port, null);
|
||||
s = socketTransportService.createTransport([], host, port, null, null);
|
||||
}
|
||||
|
||||
// Force disabling IPV6 if we aren't explicitely connecting to an IPv6 address
|
||||
|
@ -302,7 +302,7 @@ void WebrtcTCPSocket::OpenWithoutHttpProxy(nsIProxyInfo* aSocksProxyInfo) {
|
||||
|
||||
nsCOMPtr<nsISocketTransportService> sts =
|
||||
do_GetService("@mozilla.org/network/socket-transport-service;1");
|
||||
rv = sts->CreateTransport(socketTypes, host, port, aSocksProxyInfo,
|
||||
rv = sts->CreateTransport(socketTypes, host, port, aSocksProxyInfo, nullptr,
|
||||
getter_AddRefs(mTransport));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
CloseWithReason(rv);
|
||||
|
@ -185,6 +185,10 @@ class FakeSocketTransportProvider : public nsISocketTransport {
|
||||
MOZ_ASSERT(false);
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD GetRetryDnsIfPossible(bool* aRetryDns) override {
|
||||
MOZ_ASSERT(false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsITransport
|
||||
NS_IMETHOD OpenInputStream(uint32_t aFlags, uint32_t aSegmentSize,
|
||||
|
@ -252,8 +252,9 @@ nsresult TCPSocket::Init() {
|
||||
socketTypes.AppendElement("starttls"_ns);
|
||||
}
|
||||
nsCOMPtr<nsISocketTransport> transport;
|
||||
nsresult rv = sts->CreateTransport(socketTypes, NS_ConvertUTF16toUTF8(mHost),
|
||||
mPort, nullptr, getter_AddRefs(transport));
|
||||
nsresult rv =
|
||||
sts->CreateTransport(socketTypes, NS_ConvertUTF16toUTF8(mHost), mPort,
|
||||
nullptr, nullptr, getter_AddRefs(transport));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return InitWithUnconnectedTransport(transport);
|
||||
|
@ -210,5 +210,10 @@ MockedSocketTransport::GetQoSBits(uint8_t*) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
NS_IMETHODIMP
|
||||
MockedSocketTransport::SetQoSBits(uint8_t) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
NS_IMETHODIMP
|
||||
MockedSocketTransport::GetRetryDnsIfPossible(bool*) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -170,7 +170,7 @@ PresentationTCPSessionTransport::BuildTCPReceiverTransport(
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
rv = sts->CreateTransport(nsTArray<nsCString>(), serverHost, serverPort,
|
||||
nullptr, getter_AddRefs(mTransport));
|
||||
nullptr, nullptr, getter_AddRefs(mTransport));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -220,6 +220,7 @@ PresentationControlService.prototype = {
|
||||
["ssl"],
|
||||
aDeviceInfo.address,
|
||||
aDeviceInfo.port,
|
||||
null,
|
||||
null
|
||||
);
|
||||
} else {
|
||||
@ -227,6 +228,7 @@ PresentationControlService.prototype = {
|
||||
[],
|
||||
aDeviceInfo.address,
|
||||
aDeviceInfo.port,
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
@ -1120,11 +1120,11 @@ nsresult Dashboard::TestNewConnection(ConnectionData* aConnectionData) {
|
||||
AutoTArray<nsCString, 1> socketTypes = {connectionData->mProtocol};
|
||||
rv = gSocketTransportService->CreateTransport(
|
||||
socketTypes, connectionData->mHost, connectionData->mPort, nullptr,
|
||||
getter_AddRefs(connectionData->mSocket));
|
||||
nullptr, getter_AddRefs(connectionData->mSocket));
|
||||
} else {
|
||||
rv = gSocketTransportService->CreateTransport(
|
||||
nsTArray<nsCString>(), connectionData->mHost, connectionData->mPort,
|
||||
nullptr, getter_AddRefs(connectionData->mSocket));
|
||||
nullptr, nullptr, getter_AddRefs(connectionData->mSocket));
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -340,4 +340,12 @@ interface nsISocketTransport : nsITransport
|
||||
* this socket will be closed when the last private window is closed.
|
||||
*/
|
||||
[noscript] void setIsPrivate(in boolean isPrivate);
|
||||
|
||||
/**
|
||||
* If DNS is performed externally, this flag informs the caller that it may
|
||||
* retry connecting with a different DNS configuration (e.g. different IP
|
||||
* family preference). The flag is set only if a network error is encounder,
|
||||
* e.g. NS_ERROR_CONNECTION_REFUSED, NS_ERROR_RESET, etc.
|
||||
*/
|
||||
readonly attribute boolean retryDnsIfPossible;
|
||||
};
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDNSRecord;
|
||||
interface nsIFile;
|
||||
interface nsISocketTransport;
|
||||
interface nsIProxyInfo;
|
||||
@ -46,6 +47,8 @@ interface nsISocketTransportService : nsISupports
|
||||
* specifies the transport-layer proxy type to use. null if no
|
||||
* proxy. used for communicating information about proxies like
|
||||
* SOCKS (which are transparent to upper protocols).
|
||||
* @param aDnsRecord
|
||||
* the dns record to be used for the connection
|
||||
*
|
||||
* @see nsIProxiedProtocolHandler
|
||||
* @see nsIProtocolProxyService::GetProxyInfo
|
||||
@ -55,7 +58,8 @@ interface nsISocketTransportService : nsISupports
|
||||
nsISocketTransport createTransport(in Array<ACString> aSocketTypes,
|
||||
in AUTF8String aHost,
|
||||
in long aPort,
|
||||
in nsIProxyInfo aProxyInfo);
|
||||
in nsIProxyInfo aProxyInfo,
|
||||
in nsIDNSRecord dnsRecord);
|
||||
|
||||
/**
|
||||
* Create a transport built on a Unix domain socket, connecting to the
|
||||
@ -153,5 +157,6 @@ interface nsIRoutedSocketTransportService : nsISocketTransportService
|
||||
in long aPort, // origin
|
||||
in AUTF8String aHostRoute,
|
||||
in long aPortRoute,
|
||||
in nsIProxyInfo aProxyInfo);
|
||||
in nsIProxyInfo aProxyInfo,
|
||||
in nsIDNSRecord aDnsRecord);
|
||||
};
|
||||
|
@ -727,13 +727,19 @@ nsresult nsSocketTransport::Init(const nsTArray<nsCString>& types,
|
||||
const nsACString& host, uint16_t port,
|
||||
const nsACString& hostRoute,
|
||||
uint16_t portRoute,
|
||||
nsIProxyInfo* givenProxyInfo) {
|
||||
nsIProxyInfo* givenProxyInfo,
|
||||
nsIDNSRecord* dnsRecord) {
|
||||
nsCOMPtr<nsProxyInfo> proxyInfo;
|
||||
if (givenProxyInfo) {
|
||||
proxyInfo = do_QueryInterface(givenProxyInfo);
|
||||
NS_ENSURE_ARG(proxyInfo);
|
||||
}
|
||||
|
||||
if (dnsRecord) {
|
||||
mExternalDNSResolution = true;
|
||||
mDNSRecord = do_QueryInterface(dnsRecord);
|
||||
}
|
||||
|
||||
// init socket type info
|
||||
|
||||
mOriginHost = host;
|
||||
@ -990,6 +996,12 @@ nsresult nsSocketTransport::ResolveHost() {
|
||||
}
|
||||
}
|
||||
|
||||
if (mExternalDNSResolution) {
|
||||
MOZ_ASSERT(mDNSRecord);
|
||||
mState = STATE_RESOLVING;
|
||||
return PostEvent(MSG_DNS_LOOKUP_COMPLETE, NS_OK, nullptr);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDNSService> dns = nullptr;
|
||||
auto initTask = [&dns]() { dns = do_GetService(kDNSServiceCID); };
|
||||
if (!NS_IsMainThread()) {
|
||||
@ -1688,8 +1700,6 @@ bool nsSocketTransport::RecoverFromError() {
|
||||
mDNSRecord->ReportUnusable(SocketPort());
|
||||
}
|
||||
|
||||
#if defined(_WIN64) && defined(WIN95)
|
||||
// can only recover from these errors
|
||||
if (mCondition != NS_ERROR_CONNECTION_REFUSED &&
|
||||
mCondition != NS_ERROR_PROXY_CONNECTION_REFUSED &&
|
||||
mCondition != NS_ERROR_NET_TIMEOUT &&
|
||||
@ -1699,17 +1709,6 @@ bool nsSocketTransport::RecoverFromError() {
|
||||
static_cast<uint32_t>(mCondition)));
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (mCondition != NS_ERROR_CONNECTION_REFUSED &&
|
||||
mCondition != NS_ERROR_PROXY_CONNECTION_REFUSED &&
|
||||
mCondition != NS_ERROR_NET_TIMEOUT &&
|
||||
mCondition != NS_ERROR_UNKNOWN_HOST &&
|
||||
mCondition != NS_ERROR_UNKNOWN_PROXY_HOST) {
|
||||
SOCKET_LOG((" not a recoverable error %" PRIx32,
|
||||
static_cast<uint32_t>(mCondition)));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool tryAgain = false;
|
||||
|
||||
@ -1746,6 +1745,19 @@ bool nsSocketTransport::RecoverFromError() {
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
SOCKET_LOG((" trying again with next ip address\n"));
|
||||
tryAgain = true;
|
||||
} else if (mExternalDNSResolution) {
|
||||
mRetryDnsIfPossible = true;
|
||||
bool trrEnabled;
|
||||
mDNSRecord->IsTRR(&trrEnabled);
|
||||
// Bug 1648147 - If the server responded with `0.0.0.0` or `::` then we
|
||||
// should intentionally not fallback to regular DNS.
|
||||
if (trrEnabled && !StaticPrefs::network_trr_fallback_on_zero_response() &&
|
||||
((mNetAddr.raw.family == AF_INET && mNetAddr.inet.ip == 0) ||
|
||||
(mNetAddr.raw.family == AF_INET6 && mNetAddr.inet6.ip.u64[0] == 0 &&
|
||||
mNetAddr.inet6.ip.u64[1] == 0))) {
|
||||
SOCKET_LOG((" TRR returned 0.0.0.0 and there are no other IPs"));
|
||||
mRetryDnsIfPossible = false;
|
||||
}
|
||||
} else if (mConnectionFlags & RETRY_WITH_DIFFERENT_IP_FAMILY) {
|
||||
SOCKET_LOG((" failed to connect, trying with opposite ip family\n"));
|
||||
// Drop state to closed. This will trigger new round of DNS
|
||||
@ -3356,5 +3368,11 @@ nsSocketTransport::ResolvedByTRR(bool* aResolvedByTRR) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransport::GetRetryDnsIfPossible(bool* aRetryDns) {
|
||||
*aRetryDns = mRetryDnsIfPossible;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
@ -127,7 +127,7 @@ class nsSocketTransport final : public nsASocketHandler,
|
||||
// given type(s) to the given host or proxy.
|
||||
nsresult Init(const nsTArray<nsCString>& socketTypes, const nsACString& host,
|
||||
uint16_t port, const nsACString& hostRoute, uint16_t portRoute,
|
||||
nsIProxyInfo* proxyInfo);
|
||||
nsIProxyInfo* proxyInfo, nsIDNSRecord* dnsRecord);
|
||||
|
||||
// this method instructs the socket transport to use an already connected
|
||||
// socket with the given address.
|
||||
@ -461,6 +461,9 @@ class nsSocketTransport final : public nsASocketHandler,
|
||||
// Whether the port remapping has already been applied. We definitely want to
|
||||
// prevent duplicate calls in case of chaining remapping.
|
||||
bool mPortRemappingApplied = false;
|
||||
|
||||
bool mExternalDNSResolution = false;
|
||||
bool mRetryDnsIfPossible = false;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
@ -944,20 +944,23 @@ NS_IMETHODIMP
|
||||
nsSocketTransportService::CreateTransport(const nsTArray<nsCString>& types,
|
||||
const nsACString& host, int32_t port,
|
||||
nsIProxyInfo* proxyInfo,
|
||||
nsIDNSRecord* dnsRecord,
|
||||
nsISocketTransport** result) {
|
||||
return CreateRoutedTransport(types, host, port, ""_ns, 0, proxyInfo, result);
|
||||
return CreateRoutedTransport(types, host, port, ""_ns, 0, proxyInfo,
|
||||
dnsRecord, result);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransportService::CreateRoutedTransport(
|
||||
const nsTArray<nsCString>& types, const nsACString& host, int32_t port,
|
||||
const nsACString& hostRoute, int32_t portRoute, nsIProxyInfo* proxyInfo,
|
||||
nsISocketTransport** result) {
|
||||
nsIDNSRecord* dnsRecord, nsISocketTransport** result) {
|
||||
NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
|
||||
NS_ENSURE_TRUE(port >= 0 && port <= 0xFFFF, NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
RefPtr<nsSocketTransport> trans = new nsSocketTransport();
|
||||
nsresult rv = trans->Init(types, host, port, hostRoute, portRoute, proxyInfo);
|
||||
nsresult rv = trans->Init(types, host, port, hostRoute, portRoute, proxyInfo,
|
||||
dnsRecord);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -1367,7 +1367,7 @@ nsFtpState::R_pasv() {
|
||||
}
|
||||
|
||||
rv = sts->CreateTransport(nsTArray<nsCString>(), host, port,
|
||||
mChannel->ProxyInfo(),
|
||||
mChannel->ProxyInfo(), nullptr,
|
||||
getter_AddRefs(strans)); // the data socket
|
||||
if (NS_FAILED(rv)) return FTP_ERROR;
|
||||
mDataTransport = strans;
|
||||
|
@ -94,6 +94,7 @@ nsresult nsFtpControlConnection::Connect(nsIProxyInfo* proxyInfo,
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = sts->CreateTransport(nsTArray<nsCString>(), mHost, mPort, proxyInfo,
|
||||
nullptr,
|
||||
getter_AddRefs(mSocket)); // the command transport
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include "nsIDNSRecord.h"
|
||||
#include "nsIDNSService.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsURLHelper.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
|
||||
// Log on level :5, instead of default :4.
|
||||
#undef LOG
|
||||
@ -33,6 +36,7 @@ NS_INTERFACE_MAP_BEGIN(DnsAndConnectSocket)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsINamed)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDNSListener)
|
||||
NS_INTERFACE_MAP_ENTRY_CONCRETE(DnsAndConnectSocket)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
@ -41,11 +45,13 @@ DnsAndConnectSocket::DnsAndConnectSocket(ConnectionEntry* ent,
|
||||
uint32_t caps, bool speculative,
|
||||
bool isFromPredictor, bool urgentStart)
|
||||
: mTransaction(trans),
|
||||
mPrimaryTransport(false),
|
||||
mCaps(caps),
|
||||
mSpeculative(speculative),
|
||||
mUrgentStart(urgentStart),
|
||||
mIsFromPredictor(isFromPredictor),
|
||||
mEnt(ent) {
|
||||
mEnt(ent),
|
||||
mBackupTransport(true) {
|
||||
MOZ_ASSERT(ent && trans, "constructor with null arguments");
|
||||
LOG(("Creating DnsAndConnectSocket [this=%p trans=%p ent=%s key=%s]\n", this,
|
||||
trans, ent->mConnInfo->Origin(), ent->mConnInfo->HashKey().get()));
|
||||
@ -67,9 +73,10 @@ DnsAndConnectSocket::DnsAndConnectSocket(ConnectionEntry* ent,
|
||||
}
|
||||
|
||||
DnsAndConnectSocket::~DnsAndConnectSocket() {
|
||||
LOG(("Destroying DnsAndConnectSocket [this=%p]\n", this));
|
||||
MOZ_ASSERT(!mPrimaryTransport.mSocketTransport);
|
||||
MOZ_ASSERT(!mBackupTransport.mSocketTransport);
|
||||
LOG(("Destroying DnsAndConnectSocket [this=%p]\n", this));
|
||||
MOZ_ASSERT(mState == DnsAndSocketState::DONE);
|
||||
|
||||
if (mEnt) {
|
||||
bool inqueue = mEnt->RemoveDnsAndConnectSocket(this);
|
||||
@ -79,27 +86,181 @@ DnsAndConnectSocket::~DnsAndConnectSocket() {
|
||||
}
|
||||
}
|
||||
|
||||
nsresult DnsAndConnectSocket::SetupPrimaryStreams() {
|
||||
nsresult DnsAndConnectSocket::Init() {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
MOZ_ASSERT(mEnt);
|
||||
MOZ_ASSERT(mState == DnsAndSocketState::INIT);
|
||||
|
||||
nsresult rv = mPrimaryTransport.SetupStreams(this, false);
|
||||
if (mEnt->mConnInfo->GetRoutedHost().IsEmpty()) {
|
||||
mPrimaryTransport.mHost = mEnt->mConnInfo->GetOrigin();
|
||||
mBackupTransport.mHost = mEnt->mConnInfo->GetOrigin();
|
||||
} else {
|
||||
mPrimaryTransport.mHost = mEnt->mConnInfo->GetRoutedHost();
|
||||
mBackupTransport.mHost = mEnt->mConnInfo->GetRoutedHost();
|
||||
}
|
||||
|
||||
LOG(("DnsAndConnectSocket::SetupPrimaryStream [this=%p ent=%s rv=%" PRIx32
|
||||
"]",
|
||||
this, mEnt->mConnInfo->Origin(), static_cast<uint32_t>(rv)));
|
||||
CheckProxyConfig();
|
||||
|
||||
return rv;
|
||||
if (!mSkipDnsResolution) {
|
||||
nsresult rv = SetupDnsFlags();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return SetupEvent(SetupEvents::INIT_EVENT);
|
||||
}
|
||||
|
||||
nsresult DnsAndConnectSocket::SetupBackupStreams() {
|
||||
MOZ_ASSERT(mTransaction);
|
||||
void DnsAndConnectSocket::CheckProxyConfig() {
|
||||
const nsHttpConnectionInfo* ci = mEnt->mConnInfo;
|
||||
|
||||
nsresult rv = mBackupTransport.SetupStreams(this, true);
|
||||
if (ci->ProxyInfo()) {
|
||||
nsCOMPtr<nsProxyInfo> proxyInfo = ci->ProxyInfo();
|
||||
nsAutoCString proxyType(proxyInfo->Type());
|
||||
|
||||
LOG(("DnsAndConnectSocket::SetupBackupStream [this=%p ent=%s rv=%" PRIx32 "]",
|
||||
this, mEnt->mConnInfo->Origin(), static_cast<uint32_t>(rv)));
|
||||
bool proxyTransparent = false;
|
||||
if (proxyType.EqualsLiteral("socks") || proxyType.EqualsLiteral("socks4")) {
|
||||
proxyTransparent = true;
|
||||
if (proxyInfo->Flags() & nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST) {
|
||||
mProxyTransparentResolvesHost = true;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
if (mProxyTransparentResolvesHost) {
|
||||
// Name resolution is done on the server side. Just pretend
|
||||
// client resolution is complete, this will get picked up later.
|
||||
// since we don't need to do DNS now, we bypass the resolving
|
||||
// step by initializing mNetAddr to an empty address, but we
|
||||
// must keep the port. The SOCKS IO layer will use the hostname
|
||||
// we send it when it's created, rather than the empty address
|
||||
// we send with the connect call.
|
||||
mPrimaryTransport.mSkipDnsResolution = true;
|
||||
mBackupTransport.mSkipDnsResolution = true;
|
||||
mSkipDnsResolution = true;
|
||||
}
|
||||
|
||||
if (!proxyTransparent && !proxyInfo->Host().IsEmpty()) {
|
||||
mProxyNotTransparent = true;
|
||||
mPrimaryTransport.mHost = proxyInfo->Host();
|
||||
mBackupTransport.mHost = proxyInfo->Host();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult DnsAndConnectSocket::SetupDnsFlags() {
|
||||
LOG(("DnsAndConnectSocket::SetupDnsFlags [this=%p] ", this));
|
||||
|
||||
uint32_t dnsFlags = 0;
|
||||
if (mCaps & NS_HTTP_REFRESH_DNS) {
|
||||
dnsFlags = nsIDNSService::RESOLVE_BYPASS_CACHE;
|
||||
}
|
||||
if (mCaps & NS_HTTP_DISABLE_IPV4) {
|
||||
dnsFlags |= nsIDNSService::RESOLVE_DISABLE_IPV4;
|
||||
} else if (mCaps & NS_HTTP_DISABLE_IPV6) {
|
||||
dnsFlags |= nsIDNSService::RESOLVE_DISABLE_IPV6;
|
||||
} else if (mEnt->PreferenceKnown()) {
|
||||
if (mEnt->mPreferIPv6) {
|
||||
dnsFlags |= nsIDNSService::RESOLVE_DISABLE_IPV4;
|
||||
} else if (mEnt->mPreferIPv4) {
|
||||
dnsFlags |= nsIDNSService::RESOLVE_DISABLE_IPV6;
|
||||
}
|
||||
mPrimaryTransport.mRetryWithDifferentIPFamily = true;
|
||||
mBackupTransport.mRetryWithDifferentIPFamily = true;
|
||||
}
|
||||
|
||||
if (mEnt->mConnInfo->HasIPHintAddress()) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDNSService> dns =
|
||||
do_GetService("@mozilla.org/network/dns-service;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// The spec says: "If A and AAAA records for TargetName are locally
|
||||
// available, the client SHOULD ignore these hints.", so we check if the DNS
|
||||
// record is in cache before setting USE_IP_HINT_ADDRESS.
|
||||
nsCOMPtr<nsIDNSRecord> record;
|
||||
rv = dns->ResolveNative(
|
||||
mPrimaryTransport.mHost, nsIDNSService::RESOLVE_OFFLINE,
|
||||
mEnt->mConnInfo->GetOriginAttributes(), getter_AddRefs(record));
|
||||
if (NS_FAILED(rv) || !record) {
|
||||
LOG(("Setting Socket to use IP hint address"));
|
||||
dnsFlags |= nsIDNSService::RESOLVE_IP_HINT;
|
||||
}
|
||||
}
|
||||
|
||||
dnsFlags |=
|
||||
nsIDNSService::GetFlagsFromTRRMode(NS_HTTP_TRR_MODE_FROM_FLAGS(mCaps));
|
||||
|
||||
// When we get here, we are not resolving using any configured proxy likely
|
||||
// because of individual proxy setting on the request or because the host is
|
||||
// excluded from proxying. Hence, force resolution despite global proxy-DNS
|
||||
// configuration.
|
||||
dnsFlags |= nsIDNSService::RESOLVE_IGNORE_SOCKS_DNS;
|
||||
|
||||
NS_ASSERTION(!(dnsFlags & nsIDNSService::RESOLVE_DISABLE_IPV6) ||
|
||||
!(dnsFlags & nsIDNSService::RESOLVE_DISABLE_IPV4),
|
||||
"Setting both RESOLVE_DISABLE_IPV6 and RESOLVE_DISABLE_IPV4");
|
||||
|
||||
mPrimaryTransport.mDnsFlags = dnsFlags;
|
||||
mBackupTransport.mDnsFlags = dnsFlags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult DnsAndConnectSocket::SetupEvent(SetupEvents event) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
LOG(("DnsAndConnectSocket::SetupEvent state=%d event=%d", mState, event));
|
||||
switch (event) {
|
||||
case SetupEvents::INIT_EVENT: {
|
||||
MOZ_ASSERT(mState == DnsAndSocketState::INIT);
|
||||
nsresult rv = mPrimaryTransport.Init(this);
|
||||
if (NS_FAILED(rv)) {
|
||||
mState = DnsAndSocketState::DONE;
|
||||
return rv;
|
||||
}
|
||||
if (mPrimaryTransport.FirstResolving()) {
|
||||
mState = DnsAndSocketState::RESOLVING;
|
||||
} else if (mPrimaryTransport.ConnectingOrRetry()) {
|
||||
mState = DnsAndSocketState::CONNECTING;
|
||||
SetupBackupTimer();
|
||||
} else {
|
||||
MOZ_ASSERT(false);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
} break;
|
||||
case SetupEvents::RESOLVED_PRIMARY_EVENT:
|
||||
// This eventt may be posted multiple times if a DNS lookup is
|
||||
// retriggered, e.g with different parameter.
|
||||
if (mState == DnsAndSocketState::RESOLVING) {
|
||||
mState = DnsAndSocketState::CONNECTING;
|
||||
SetupBackupTimer();
|
||||
}
|
||||
break;
|
||||
case SetupEvents::PRIMARY_DONE_EVENT:
|
||||
MOZ_ASSERT((mState == DnsAndSocketState::RESOLVING) ||
|
||||
(mState == DnsAndSocketState::CONNECTING) ||
|
||||
(mState == DnsAndSocketState::ONE_CONNECTED));
|
||||
CancelBackupTimer();
|
||||
mBackupTransport.CancelDnsResolution();
|
||||
if (mBackupTransport.ConnectingOrRetry()) {
|
||||
mState = DnsAndSocketState::ONE_CONNECTED;
|
||||
} else {
|
||||
mState = DnsAndSocketState::DONE;
|
||||
}
|
||||
break;
|
||||
case SetupEvents::BACKUP_DONE_EVENT:
|
||||
MOZ_ASSERT((mState == DnsAndSocketState::CONNECTING) ||
|
||||
(mState == DnsAndSocketState::ONE_CONNECTED));
|
||||
if (mPrimaryTransport.ConnectingOrRetry()) {
|
||||
mState = DnsAndSocketState::ONE_CONNECTED;
|
||||
} else {
|
||||
mState = DnsAndSocketState::DONE;
|
||||
}
|
||||
break;
|
||||
case SetupEvents::BACKUP_TIMER_FIRED_EVENT:
|
||||
MOZ_ASSERT(mState == DnsAndSocketState::CONNECTING);
|
||||
mBackupTransport.Init(this);
|
||||
}
|
||||
LOG(("DnsAndConnectSocket::SetupEvent state=%d", mState));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void DnsAndConnectSocket::SetupBackupTimer() {
|
||||
@ -109,7 +270,7 @@ void DnsAndConnectSocket::SetupBackupTimer() {
|
||||
|
||||
// When using Fast Open the correct transport will be setup for sure (it is
|
||||
// guaranteed), but it can be that it will happened a bit later.
|
||||
if (timeout && !mSpeculative) {
|
||||
if (timeout && !mSpeculative && !mIsHttp3) {
|
||||
// Setup the timer that will establish a backup socket
|
||||
// if we do not get a writable event on the main one.
|
||||
// We do this because a lost SYN takes a very long time
|
||||
@ -157,6 +318,8 @@ void DnsAndConnectSocket::Abandon() {
|
||||
// Stop the timer - we don't want any new backups.
|
||||
CancelBackupTimer();
|
||||
|
||||
mState = DnsAndSocketState::DONE;
|
||||
|
||||
// Remove the half open from the connection entry.
|
||||
if (mEnt) {
|
||||
mEnt->mDoNotDestroy = false;
|
||||
@ -178,11 +341,12 @@ DnsAndConnectSocket::Notify(nsITimer* timer) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
MOZ_ASSERT(timer == mSynTimer, "wrong timer");
|
||||
|
||||
MOZ_ASSERT(!mBackupTransport.mDNSRequest);
|
||||
MOZ_ASSERT(!mBackupTransport.mSocketTransport);
|
||||
MOZ_ASSERT(mSynTimer);
|
||||
MOZ_ASSERT(mEnt);
|
||||
|
||||
DebugOnly<nsresult> rv = SetupBackupStreams();
|
||||
DebugOnly<nsresult> rv = SetupEvent(BACKUP_TIMER_FIRED_EVENT);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
// Keeping the reference to the timer to remember we have already
|
||||
@ -197,6 +361,50 @@ DnsAndConnectSocket::GetName(nsACString& aName) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DnsAndConnectSocket::OnLookupComplete(nsICancelable* request, nsIDNSRecord* rec,
|
||||
nsresult status) {
|
||||
LOG(("DnsAndConnectSocket::OnLookupComplete: this=%p status %" PRIx32 ".",
|
||||
this, static_cast<uint32_t>(status)));
|
||||
|
||||
RefPtr<DnsAndConnectSocket> deleteProtector(this);
|
||||
|
||||
if (!IsPrimary(request) && !IsBackup(request)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (IsPrimary(request) && NS_SUCCEEDED(status)) {
|
||||
mTransaction->OnTransportStatus(nullptr, NS_NET_STATUS_RESOLVED_HOST, 0);
|
||||
}
|
||||
|
||||
// When using a HTTP proxy, NS_ERROR_UNKNOWN_HOST means the HTTP
|
||||
// proxy host is not found, so we fixup the error code.
|
||||
// For SOCKS proxies (mProxyTransparent == true), the socket
|
||||
// transport resolves the real host here, so there's no fixup
|
||||
// (see bug 226943).
|
||||
if (mProxyNotTransparent && (status == NS_ERROR_UNKNOWN_HOST)) {
|
||||
status = NS_ERROR_UNKNOWN_PROXY_HOST;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
// remember if it was primary because TransportSetups will delete the ref to
|
||||
// the DNS request and check cannot be performed later.
|
||||
bool isPrimary = IsPrimary(request);
|
||||
if (IsPrimary(request)) {
|
||||
rv = mPrimaryTransport.OnLookupComplete(this, rec, status);
|
||||
if (mPrimaryTransport.ConnectingOrRetry()) {
|
||||
SetupEvent(SetupEvents::RESOLVED_PRIMARY_EVENT);
|
||||
}
|
||||
} else {
|
||||
rv = mBackupTransport.OnLookupComplete(this, rec, status);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
SetupConn(isPrimary, rv);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// method for nsIAsyncOutputStreamCallback
|
||||
NS_IMETHODIMP
|
||||
DnsAndConnectSocket::OnOutputStreamReady(nsIAsyncOutputStream* out) {
|
||||
@ -206,33 +414,68 @@ DnsAndConnectSocket::OnOutputStreamReady(nsIAsyncOutputStream* out) {
|
||||
MOZ_ASSERT(IsPrimary(out) || IsBackup(out), "stream mismatch");
|
||||
MOZ_ASSERT(mEnt);
|
||||
|
||||
RefPtr<DnsAndConnectSocket> deleteProtector(this);
|
||||
|
||||
LOG(("DnsAndConnectSocket::OnOutputStreamReady [this=%p ent=%s %s]\n", this,
|
||||
mEnt->mConnInfo->Origin(), IsPrimary(out) ? "primary" : "backup"));
|
||||
|
||||
// Remember if it was primary or backup reuest.
|
||||
bool isPrimary = IsPrimary(out);
|
||||
nsresult rv = NS_OK;
|
||||
if (isPrimary) {
|
||||
rv = mPrimaryTransport.CheckConnectedResult(this);
|
||||
if (!mPrimaryTransport.DoneConnecting()) {
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT((NS_SUCCEEDED(rv) &&
|
||||
(mPrimaryTransport.mState ==
|
||||
TransportSetup::TransportSetupState::CONNECTING_DONE) &&
|
||||
mPrimaryTransport.mSocketTransport) ||
|
||||
(NS_FAILED(rv) &&
|
||||
(mPrimaryTransport.mState ==
|
||||
TransportSetup::TransportSetupState::DONE) &&
|
||||
!mPrimaryTransport.mSocketTransport));
|
||||
} else if (IsBackup(out)) {
|
||||
rv = mBackupTransport.CheckConnectedResult(this);
|
||||
if (!mBackupTransport.DoneConnecting()) {
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT((NS_SUCCEEDED(rv) &&
|
||||
(mBackupTransport.mState ==
|
||||
TransportSetup::TransportSetupState::CONNECTING_DONE) &&
|
||||
mBackupTransport.mSocketTransport) ||
|
||||
(NS_FAILED(rv) &&
|
||||
(mBackupTransport.mState ==
|
||||
TransportSetup::TransportSetupState::DONE) &&
|
||||
!mBackupTransport.mSocketTransport));
|
||||
} else {
|
||||
MOZ_ASSERT(false, "unexpected stream");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
mEnt->mDoNotDestroy = true;
|
||||
gHttpHandler->ConnMgr()->RecvdConnect();
|
||||
|
||||
CancelBackupTimer();
|
||||
|
||||
nsresult rv = SetupConn(out);
|
||||
rv = SetupConn(isPrimary, rv);
|
||||
if (mEnt) {
|
||||
mEnt->mDoNotDestroy = false;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult DnsAndConnectSocket::SetupConn(nsIAsyncOutputStream* out) {
|
||||
nsresult DnsAndConnectSocket::SetupConn(bool isPrimary, nsresult status) {
|
||||
// assign the new socket to the http connection
|
||||
RefPtr<HttpConnectionBase> conn;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (IsPrimary(out)) {
|
||||
rv = mPrimaryTransport.SetupConn(mTransaction, mEnt, getter_AddRefs(conn));
|
||||
} else if (IsBackup(out)) {
|
||||
rv = mBackupTransport.SetupConn(mTransaction, mEnt, getter_AddRefs(conn));
|
||||
if (isPrimary) {
|
||||
SetupEvent(SetupEvents::PRIMARY_DONE_EVENT);
|
||||
rv = mPrimaryTransport.SetupConn(mTransaction, mEnt, status,
|
||||
getter_AddRefs(conn));
|
||||
} else {
|
||||
MOZ_ASSERT(false, "unexpected stream");
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
SetupEvent(SetupEvents::BACKUP_DONE_EVENT);
|
||||
rv = mBackupTransport.SetupConn(mTransaction, mEnt, status,
|
||||
getter_AddRefs(conn));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
||||
@ -390,12 +633,13 @@ DnsAndConnectSocket::OnTransportStatus(nsITransport* trans, nsresult status,
|
||||
// Send this status event only if the transaction is still pending,
|
||||
// i.e. it has not found a free already connected socket.
|
||||
// Sockets in halfOpen state can only get following events:
|
||||
// NS_NET_STATUS_RESOLVING_HOST, NS_NET_STATUS_RESOLVED_HOST,
|
||||
// NS_NET_STATUS_CONNECTING_TO and NS_NET_STATUS_CONNECTED_TO.
|
||||
// mBackupTransport is only started after
|
||||
// NS_NET_STATUS_CONNECTING_TO of mSocketTransport, so ignore all
|
||||
// mBackupTransport events until NS_NET_STATUS_CONNECTED_TO.
|
||||
// mBackupTransport must be connected before mSocketTransport.
|
||||
// NS_NET_STATUS_CONNECTING_TO of mSocketTransport, so ignore
|
||||
// NS_NET_STATUS_CONNECTING_TO event for mBackupTransport and
|
||||
// send NS_NET_STATUS_CONNECTED_TO.
|
||||
// mBackupTransport must be connected before mSocketTransport(e.g.
|
||||
// mPrimaryTransport.mSocketTransport != nullpttr).
|
||||
mTransaction->OnTransportStatus(trans, status, progress);
|
||||
}
|
||||
}
|
||||
@ -413,8 +657,6 @@ DnsAndConnectSocket::OnTransportStatus(nsITransport* trans, nsresult status,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mPrimaryStreamStatus = status;
|
||||
|
||||
// if we are doing spdy coalescing and haven't recorded the ip address
|
||||
// for this entry before then make the hash key if our dns lookup
|
||||
// just completed. We can't do coalescing if using a proxy because the
|
||||
@ -471,34 +713,6 @@ DnsAndConnectSocket::OnTransportStatus(nsITransport* trans, nsresult status,
|
||||
}
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case NS_NET_STATUS_CONNECTING_TO:
|
||||
// Passed DNS resolution, now trying to connect, start the backup timer
|
||||
// only prevent creating another backup transport.
|
||||
// We also check for mEnt presence to not instantiate the timer after
|
||||
// this half open socket has already been abandoned. It may happen
|
||||
// when we get this notification right between main-thread calls to
|
||||
// nsHttpConnectionMgr::Shutdown and nsSocketTransportService::Shutdown
|
||||
// where the first abandons all half open socket instances and only
|
||||
// after that the second stops the socket thread.
|
||||
// Http3 has its own syn-retransmission, therefore it does not need a
|
||||
// backup connection.
|
||||
if (mEnt && !mBackupTransport.mSocketTransport && !mSynTimer &&
|
||||
!mIsHttp3) {
|
||||
SetupBackupTimer();
|
||||
}
|
||||
break;
|
||||
|
||||
case NS_NET_STATUS_CONNECTED_TO:
|
||||
// TCP connection's up, now transfer or SSL negotiantion starts,
|
||||
// no need for backup socket
|
||||
CancelBackupTimer();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -510,6 +724,10 @@ bool DnsAndConnectSocket::IsPrimary(nsIAsyncOutputStream* out) {
|
||||
return out == mPrimaryTransport.mStreamOut;
|
||||
}
|
||||
|
||||
bool DnsAndConnectSocket::IsPrimary(nsICancelable* dnsRequest) {
|
||||
return dnsRequest == mPrimaryTransport.mDNSRequest;
|
||||
}
|
||||
|
||||
bool DnsAndConnectSocket::IsBackup(nsITransport* trans) {
|
||||
return trans == mBackupTransport.mSocketTransport;
|
||||
}
|
||||
@ -518,6 +736,10 @@ bool DnsAndConnectSocket::IsBackup(nsIAsyncOutputStream* out) {
|
||||
return out == mBackupTransport.mStreamOut;
|
||||
}
|
||||
|
||||
bool DnsAndConnectSocket::IsBackup(nsICancelable* dnsRequest) {
|
||||
return dnsRequest == mBackupTransport.mDNSRequest;
|
||||
}
|
||||
|
||||
// method for nsIInterfaceRequestor
|
||||
NS_IMETHODIMP
|
||||
DnsAndConnectSocket::GetInterface(const nsIID& iid, void** result) {
|
||||
@ -560,7 +782,7 @@ bool DnsAndConnectSocket::Claim() {
|
||||
|
||||
// Http3 has its own syn-retransmission, therefore it does not need a
|
||||
// backup connection.
|
||||
if ((mPrimaryStreamStatus == NS_NET_STATUS_CONNECTING_TO) && mEnt &&
|
||||
if (mPrimaryTransport.ConnectingOrRetry() && mEnt &&
|
||||
!mBackupTransport.mSocketTransport && !mSynTimer && !mIsHttp3) {
|
||||
SetupBackupTimer();
|
||||
}
|
||||
@ -590,7 +812,43 @@ void DnsAndConnectSocket::CloseTransports(nsresult error) {
|
||||
}
|
||||
}
|
||||
|
||||
DnsAndConnectSocket::TransportSetup::TransportSetup(bool isBackup)
|
||||
: mState(TransportSetup::TransportSetupState::INIT), mIsBackup(isBackup) {}
|
||||
|
||||
nsresult DnsAndConnectSocket::TransportSetup::Init(
|
||||
DnsAndConnectSocket* dnsAndSock) {
|
||||
nsresult rv;
|
||||
mSynStarted = TimeStamp::Now();
|
||||
if (mSkipDnsResolution) {
|
||||
mState = TransportSetup::TransportSetupState::CONNECTING;
|
||||
rv = SetupStreams(dnsAndSock);
|
||||
} else {
|
||||
mState = TransportSetup::TransportSetupState::RESOLVING;
|
||||
rv = ResolveHost(dnsAndSock);
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
CloseAll();
|
||||
mState = TransportSetup::TransportSetupState::DONE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void DnsAndConnectSocket::TransportSetup::CancelDnsResolution() {
|
||||
if (mDNSRequest) {
|
||||
mDNSRequest->Cancel(NS_ERROR_ABORT);
|
||||
mDNSRequest = nullptr;
|
||||
}
|
||||
if (mState == TransportSetup::TransportSetupState::RESOLVING) {
|
||||
mState = TransportSetup::TransportSetupState::INIT;
|
||||
}
|
||||
}
|
||||
|
||||
void DnsAndConnectSocket::TransportSetup::Abandon() {
|
||||
CloseAll();
|
||||
mState = TransportSetup::TransportSetupState::DONE;
|
||||
}
|
||||
|
||||
void DnsAndConnectSocket::TransportSetup::CloseAll() {
|
||||
// Tell socket (and backup socket) to forget the half open socket.
|
||||
if (mSocketTransport) {
|
||||
mSocketTransport->SetEventSink(nullptr, nullptr);
|
||||
@ -610,10 +868,71 @@ void DnsAndConnectSocket::TransportSetup::Abandon() {
|
||||
mStreamIn->AsyncWait(nullptr, 0, 0, nullptr);
|
||||
mStreamIn = nullptr;
|
||||
}
|
||||
|
||||
if (mDNSRequest) {
|
||||
mDNSRequest->Cancel(NS_ERROR_ABORT);
|
||||
mDNSRequest = nullptr;
|
||||
}
|
||||
|
||||
mConnectedOK = false;
|
||||
}
|
||||
|
||||
nsresult DnsAndConnectSocket::TransportSetup::CheckConnectedResult(
|
||||
DnsAndConnectSocket* dnsAndSock) {
|
||||
mState = TransportSetup::TransportSetupState::CONNECTING_DONE;
|
||||
|
||||
if (mSkipDnsResolution) {
|
||||
return NS_OK;
|
||||
}
|
||||
bool retryDns = false;
|
||||
mSocketTransport->GetRetryDnsIfPossible(&retryDns);
|
||||
if (!retryDns) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool retry = false;
|
||||
if (mRetryWithDifferentIPFamily) {
|
||||
mRetryWithDifferentIPFamily = false;
|
||||
mDnsFlags ^= (nsIDNSService::RESOLVE_DISABLE_IPV6 |
|
||||
nsIDNSService::RESOLVE_DISABLE_IPV4);
|
||||
mResetFamilyPreference = true;
|
||||
retry = true;
|
||||
} else if (!(mDnsFlags & nsIDNSService::RESOLVE_DISABLE_TRR)) {
|
||||
bool trrEnabled;
|
||||
mDNSRecord->IsTRR(&trrEnabled);
|
||||
if (trrEnabled) {
|
||||
uint32_t trrMode = 0;
|
||||
mDNSRecord->GetEffectiveTRRMode(&trrMode);
|
||||
// If current trr mode is trr only, we should not retry.
|
||||
if (trrMode != 3) {
|
||||
// Drop state to closed. This will trigger a new round of
|
||||
// DNS resolving. Bypass the cache this time since the
|
||||
// cached data came from TRR and failed already!
|
||||
LOG((" failed to connect with TRR enabled, try w/o\n"));
|
||||
mDnsFlags |= nsIDNSService::RESOLVE_DISABLE_TRR |
|
||||
nsIDNSService::RESOLVE_BYPASS_CACHE |
|
||||
nsIDNSService::RESOLVE_REFRESH_CACHE;
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (retry) {
|
||||
CloseAll();
|
||||
mState = TransportSetup::TransportSetupState::RESOLVING;
|
||||
nsresult rv = ResolveHost(dnsAndSock);
|
||||
if (NS_FAILED(rv)) {
|
||||
CloseAll();
|
||||
mState = TransportSetup::TransportSetupState::DONE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult DnsAndConnectSocket::TransportSetup::SetupConn(
|
||||
nsAHttpTransaction* transaction, ConnectionEntry* ent,
|
||||
nsAHttpTransaction* transaction, ConnectionEntry* ent, nsresult status,
|
||||
HttpConnectionBase** connection) {
|
||||
RefPtr<HttpConnectionBase> conn;
|
||||
if (!ent->mConnInfo->IsHttp3()) {
|
||||
@ -640,29 +959,34 @@ nsresult DnsAndConnectSocket::TransportSetup::SetupConn(
|
||||
transaction->GetSecurityCallbacks(getter_AddRefs(callbacks));
|
||||
nsresult rv = conn->Init(
|
||||
ent->mConnInfo, gHttpHandler->ConnMgr()->mMaxRequestDelay,
|
||||
mSocketTransport, mStreamIn, mStreamOut, mConnectedOK, callbacks,
|
||||
mSocketTransport, mStreamIn, mStreamOut, mConnectedOK, status, callbacks,
|
||||
PR_MillisecondsToInterval(static_cast<uint32_t>(
|
||||
(TimeStamp::Now() - mSynStarted).ToMilliseconds())));
|
||||
|
||||
bool resetPreference = false;
|
||||
mSocketTransport->GetResetIPFamilyPreference(&resetPreference);
|
||||
if (resetPreference) {
|
||||
if (mResetFamilyPreference ||
|
||||
(mSocketTransport &&
|
||||
NS_SUCCEEDED(
|
||||
mSocketTransport->GetResetIPFamilyPreference(&resetPreference)) &&
|
||||
resetPreference)) {
|
||||
ent->ResetIPFamilyPreference();
|
||||
}
|
||||
|
||||
NetAddr peeraddr;
|
||||
if (NS_SUCCEEDED(mSocketTransport->GetPeerAddr(&peeraddr))) {
|
||||
if (mSocketTransport &&
|
||||
NS_SUCCEEDED(mSocketTransport->GetPeerAddr(&peeraddr))) {
|
||||
ent->RecordIPFamilyPreference(peeraddr.raw.family);
|
||||
}
|
||||
conn.forget(connection);
|
||||
mSocketTransport = nullptr;
|
||||
mStreamOut = nullptr;
|
||||
mStreamIn = nullptr;
|
||||
mState = TransportSetup::TransportSetupState::DONE;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult DnsAndConnectSocket::TransportSetup::SetupStreams(
|
||||
DnsAndConnectSocket *dnsAndSock, bool isBackup) {
|
||||
DnsAndConnectSocket* dnsAndSock) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
|
||||
MOZ_ASSERT(dnsAndSock->mEnt);
|
||||
@ -700,7 +1024,8 @@ nsresult DnsAndConnectSocket::TransportSetup::SetupStreams(
|
||||
if (routedSTS) {
|
||||
rv = routedSTS->CreateRoutedTransport(
|
||||
socketTypes, ci->GetOrigin(), ci->OriginPort(), ci->GetRoutedHost(),
|
||||
ci->RoutedPort(), ci->ProxyInfo(), getter_AddRefs(socketTransport));
|
||||
ci->RoutedPort(), ci->ProxyInfo(), mDNSRecord,
|
||||
getter_AddRefs(socketTransport));
|
||||
} else {
|
||||
if (!ci->GetRoutedHost().IsEmpty()) {
|
||||
// There is a route requested, but the legacy nsISocketTransportService
|
||||
@ -714,7 +1039,8 @@ nsresult DnsAndConnectSocket::TransportSetup::SetupStreams(
|
||||
}
|
||||
|
||||
rv = sts->CreateTransport(socketTypes, ci->GetOrigin(), ci->OriginPort(),
|
||||
ci->ProxyInfo(), getter_AddRefs(socketTransport));
|
||||
ci->ProxyInfo(), mDNSRecord,
|
||||
getter_AddRefs(socketTransport));
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -750,15 +1076,13 @@ nsresult DnsAndConnectSocket::TransportSetup::SetupStreams(
|
||||
if (ci->HasIPHintAddress()) {
|
||||
nsCOMPtr<nsIDNSService> dns =
|
||||
do_GetService("@mozilla.org/network/dns-service;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// The spec says: "If A and AAAA records for TargetName are locally
|
||||
// available, the client SHOULD ignore these hints.", so we check if the DNS
|
||||
// record is in cache before setting USE_IP_HINT_ADDRESS.
|
||||
nsCOMPtr<nsIDNSRecord> record;
|
||||
rv = dns->ResolveNative(ci->GetRoutedHost(), nsIDNSService::RESOLVE_OFFLINE,
|
||||
rv = dns->ResolveNative(mHost, nsIDNSService::RESOLVE_OFFLINE,
|
||||
dnsAndSock->mEnt->mConnInfo->GetOriginAttributes(),
|
||||
getter_AddRefs(record));
|
||||
if (NS_FAILED(rv) || !record) {
|
||||
@ -785,12 +1109,12 @@ nsresult DnsAndConnectSocket::TransportSetup::SetupStreams(
|
||||
// From the same reason, let the backup socket fail faster to try the other
|
||||
// family.
|
||||
uint16_t fallbackTimeout =
|
||||
isBackup ? gHttpHandler->GetFallbackSynTimeout() : 0;
|
||||
mIsBackup ? gHttpHandler->GetFallbackSynTimeout() : 0;
|
||||
if (fallbackTimeout) {
|
||||
socketTransport->SetTimeout(nsISocketTransport::TIMEOUT_CONNECT,
|
||||
fallbackTimeout);
|
||||
}
|
||||
} else if (isBackup && gHttpHandler->FastFallbackToIPv4()) {
|
||||
} else if (mIsBackup && gHttpHandler->FastFallbackToIPv4()) {
|
||||
// For backup connections, we disable IPv6. That's because some users have
|
||||
// broken IPv6 connectivity (leading to very long timeouts), and disabling
|
||||
// IPv6 on the backup connection gives them a much better user experience
|
||||
@ -842,7 +1166,6 @@ nsresult DnsAndConnectSocket::TransportSetup::SetupStreams(
|
||||
getter_AddRefs(sin));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mSynStarted = TimeStamp::Now();
|
||||
mSocketTransport = socketTransport.forget();
|
||||
mStreamIn = do_QueryInterface(sin);
|
||||
mStreamOut = do_QueryInterface(sout);
|
||||
@ -855,5 +1178,88 @@ nsresult DnsAndConnectSocket::TransportSetup::SetupStreams(
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult DnsAndConnectSocket::TransportSetup::ResolveHost(
|
||||
DnsAndConnectSocket* dnsAndSock) {
|
||||
LOG(("DnsAndConnectSocket::TransportSetup::ResolveHost [this=%p %s%s]", this,
|
||||
PromiseFlatCString(mHost).get(),
|
||||
(mDnsFlags & nsIDNSService::RESOLVE_BYPASS_CACHE) ? " bypass cache"
|
||||
: ""));
|
||||
nsCOMPtr<nsIDNSService> dns = nullptr;
|
||||
auto initTask = [&dns]() { dns = do_GetService(NS_DNSSERVICE_CID); };
|
||||
if (!NS_IsMainThread()) {
|
||||
// Forward to the main thread synchronously.
|
||||
RefPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
if (!mainThread) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
SyncRunnable::DispatchToThread(
|
||||
mainThread,
|
||||
new SyncRunnable(NS_NewRunnableFunction(
|
||||
"nsSocketTransport::ResolveHost->GetDNSService", initTask)));
|
||||
} else {
|
||||
initTask();
|
||||
}
|
||||
if (!dns) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!mIsBackup) {
|
||||
dnsAndSock->mTransaction->OnTransportStatus(
|
||||
nullptr, NS_NET_STATUS_RESOLVING_HOST, 0);
|
||||
}
|
||||
|
||||
return dns->AsyncResolveNative(
|
||||
mHost, nsIDNSService::RESOLVE_TYPE_DEFAULT, mDnsFlags, nullptr,
|
||||
dnsAndSock, gSocketTransportService,
|
||||
dnsAndSock->mEnt->mConnInfo->GetOriginAttributes(),
|
||||
getter_AddRefs(mDNSRequest));
|
||||
}
|
||||
|
||||
nsresult DnsAndConnectSocket::TransportSetup::OnLookupComplete(
|
||||
DnsAndConnectSocket* dnsAndSock, nsIDNSRecord* rec, nsresult status) {
|
||||
mDNSRequest = nullptr;
|
||||
if (NS_SUCCEEDED(status)) {
|
||||
mDNSRecord = do_QueryInterface(rec);
|
||||
MOZ_ASSERT(mDNSRecord);
|
||||
|
||||
nsresult rv = SetupStreams(dnsAndSock);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mState = TransportSetup::TransportSetupState::CONNECTING;
|
||||
} else {
|
||||
CloseAll();
|
||||
mState = TransportSetup::TransportSetupState::DONE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// DNS lookup status failed
|
||||
|
||||
bool retry = false;
|
||||
if (mDnsFlags & nsIDNSService::RESOLVE_IP_HINT) {
|
||||
mDnsFlags &= ~nsIDNSService::RESOLVE_IP_HINT;
|
||||
retry = true;
|
||||
} else if ((status == NS_ERROR_UNKNOWN_HOST) && mRetryWithDifferentIPFamily) {
|
||||
mRetryWithDifferentIPFamily = false;
|
||||
mDnsFlags ^= (nsIDNSService::RESOLVE_DISABLE_IPV6 |
|
||||
nsIDNSService::RESOLVE_DISABLE_IPV4);
|
||||
mResetFamilyPreference = true;
|
||||
retry = true;
|
||||
}
|
||||
|
||||
if (retry) {
|
||||
mState = TransportSetup::TransportSetupState::RETRY_RESOLVING;
|
||||
nsresult rv = ResolveHost(dnsAndSock);
|
||||
if (NS_FAILED(rv)) {
|
||||
CloseAll();
|
||||
mState = TransportSetup::TransportSetupState::DONE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
mState = TransportSetup::TransportSetupState::DONE;
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include "nsHttpConnection.h"
|
||||
#include "nsHttpTransaction.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
#include "nsICancelable.h"
|
||||
#include "nsIDNSListener.h"
|
||||
#include "nsIDNSRecord.h"
|
||||
#include "nsINamed.h"
|
||||
#include "nsITransport.h"
|
||||
#include "nsWeakReference.h"
|
||||
@ -35,7 +38,8 @@ class DnsAndConnectSocket final : public nsIOutputStreamCallback,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsITimerCallback,
|
||||
public nsINamed,
|
||||
public nsSupportsWeakReference {
|
||||
public nsSupportsWeakReference,
|
||||
public nsIDNSListener {
|
||||
~DnsAndConnectSocket();
|
||||
|
||||
public:
|
||||
@ -46,12 +50,13 @@ class DnsAndConnectSocket final : public nsIOutputStreamCallback,
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
NS_DECL_NSINAMED
|
||||
NS_DECL_NSIDNSLISTENER
|
||||
|
||||
DnsAndConnectSocket(ConnectionEntry* ent, nsAHttpTransaction* trans,
|
||||
uint32_t caps, bool speculative, bool isFromPredictor,
|
||||
bool urgentStart);
|
||||
|
||||
[[nodiscard]] nsresult SetupPrimaryStreams();
|
||||
[[nodiscard]] nsresult Init();
|
||||
void Abandon();
|
||||
double Duration(TimeStamp epoch);
|
||||
void CloseTransports(nsresult error);
|
||||
@ -75,29 +80,110 @@ class DnsAndConnectSocket final : public nsIOutputStreamCallback,
|
||||
void Unclaim();
|
||||
|
||||
private:
|
||||
/**
|
||||
* State:
|
||||
* INIT: initial state. From this state:
|
||||
* 1) change the state to RESOLVING and start the primary DNS lookup
|
||||
* if mSkipDnsResolution is false,
|
||||
* 2) or the lookup is skip and the state changes to CONNECTING and
|
||||
* start the backup timer.
|
||||
* 3) or changes to DONE in case of an error.
|
||||
* RESOLVING: the primary DNS resolution is in progress. From this state
|
||||
* we transition into CONNECTING or DONE.
|
||||
* CONNECTING: We change to this state when the primary connection has
|
||||
* started. At that point the backup timer is started.
|
||||
* ONE_CONNECTED: We change into this state when one of the connections
|
||||
* is connected and the second is in progres.
|
||||
* DONE
|
||||
*
|
||||
* Events:
|
||||
* INIT_EVENT: Start the primary dns resolution (if mSkipDnsResolution is
|
||||
* false), otherwise start the primary connection.
|
||||
* RESOLVED_PRIMARY_EVENT: the primary DNS resolution is done. This event
|
||||
* may be resent due to DNS retries
|
||||
* CONNECTED_EVENT: A connecion (primary or backup) is done
|
||||
*/
|
||||
enum DnsAndSocketState {
|
||||
INIT,
|
||||
RESOLVING,
|
||||
CONNECTING,
|
||||
ONE_CONNECTED,
|
||||
DONE
|
||||
} mState = INIT;
|
||||
|
||||
enum SetupEvents {
|
||||
INIT_EVENT,
|
||||
RESOLVED_PRIMARY_EVENT,
|
||||
PRIMARY_DONE_EVENT,
|
||||
BACKUP_DONE_EVENT,
|
||||
BACKUP_TIMER_FIRED_EVENT
|
||||
};
|
||||
|
||||
// This structure is responsible for performing DNS lookup, creating socket
|
||||
// and connecting the socket.
|
||||
struct TransportSetup {
|
||||
enum TransportSetupState {
|
||||
INIT,
|
||||
RESOLVING,
|
||||
RETRY_RESOLVING,
|
||||
CONNECTING,
|
||||
CONNECTING_DONE,
|
||||
DONE
|
||||
} mState;
|
||||
|
||||
bool FirstResolving() {
|
||||
return mState == TransportSetup::TransportSetupState::RESOLVING;
|
||||
}
|
||||
bool ConnectingOrRetry() {
|
||||
return (mState == TransportSetup::TransportSetupState::CONNECTING) ||
|
||||
(mState == TransportSetup::TransportSetupState::RETRY_RESOLVING) ||
|
||||
(mState == TransportSetup::TransportSetupState::CONNECTING_DONE);
|
||||
}
|
||||
bool DoneConnecting() {
|
||||
return (mState == TransportSetup::TransportSetupState::CONNECTING_DONE) ||
|
||||
(mState == TransportSetup::TransportSetupState::DONE);
|
||||
}
|
||||
|
||||
nsCString mHost;
|
||||
nsCOMPtr<nsICancelable> mDNSRequest;
|
||||
nsCOMPtr<nsIDNSAddrRecord> mDNSRecord;
|
||||
uint32_t mDnsFlags = 0;
|
||||
bool mRetryWithDifferentIPFamily = false;
|
||||
bool mResetFamilyPreference = false;
|
||||
bool mSkipDnsResolution = false;
|
||||
|
||||
nsCOMPtr<nsISocketTransport> mSocketTransport;
|
||||
nsCOMPtr<nsIAsyncOutputStream> mStreamOut;
|
||||
nsCOMPtr<nsIAsyncInputStream> mStreamIn;
|
||||
TimeStamp mSynStarted;
|
||||
bool mConnectedOK = false;
|
||||
bool mIsBackup;
|
||||
|
||||
explicit TransportSetup(bool isBackup);
|
||||
|
||||
nsresult Init(DnsAndConnectSocket* dnsAndSock);
|
||||
void CancelDnsResolution();
|
||||
void Abandon();
|
||||
void CloseAll();
|
||||
nsresult SetupConn(nsAHttpTransaction* transaction, ConnectionEntry* ent,
|
||||
HttpConnectionBase** connection);
|
||||
[[nodiscard]] nsresult SetupStreams(DnsAndConnectSocket* dnsAndSock,
|
||||
bool isBackup);
|
||||
nsresult status, HttpConnectionBase** connection);
|
||||
[[nodiscard]] nsresult SetupStreams(DnsAndConnectSocket* dnsAndSock);
|
||||
nsresult ResolveHost(DnsAndConnectSocket* dnsAndSock);
|
||||
nsresult OnLookupComplete(DnsAndConnectSocket* dnsAndSock,
|
||||
nsIDNSRecord* rec, nsresult status);
|
||||
nsresult CheckConnectedResult(DnsAndConnectSocket* dnsAndSock);
|
||||
};
|
||||
|
||||
[[nodiscard]] nsresult SetupBackupStreams();
|
||||
[[nodiscard]] nsresult SetupStreams(bool isBackup);
|
||||
nsresult SetupConn(nsIAsyncOutputStream* out);
|
||||
nsresult SetupConn(bool isPrimary, nsresult status);
|
||||
void SetupBackupTimer();
|
||||
void CancelBackupTimer();
|
||||
|
||||
bool IsPrimary(nsITransport* trans);
|
||||
bool IsPrimary(nsIAsyncOutputStream* out);
|
||||
bool IsPrimary(nsICancelable* dnsRequest);
|
||||
bool IsBackup(nsITransport* trans);
|
||||
bool IsBackup(nsIAsyncOutputStream* out);
|
||||
bool IsBackup(nsICancelable* dnsRequest);
|
||||
|
||||
// To find out whether |mTransaction| is still in the connection entry's
|
||||
// pending queue. If the transaction is found and |removeWhenFound| is
|
||||
@ -105,6 +191,10 @@ class DnsAndConnectSocket final : public nsIOutputStreamCallback,
|
||||
already_AddRefed<PendingTransactionInfo> FindTransactionHelper(
|
||||
bool removeWhenFound);
|
||||
|
||||
void CheckProxyConfig();
|
||||
nsresult SetupDnsFlags();
|
||||
nsresult SetupEvent(SetupEvents event);
|
||||
|
||||
RefPtr<nsAHttpTransaction> mTransaction;
|
||||
bool mDispatchedMTransaction = false;
|
||||
|
||||
@ -142,13 +232,16 @@ class DnsAndConnectSocket final : public nsIOutputStreamCallback,
|
||||
// case we can free this transaction to be claimed by other
|
||||
// transactions.
|
||||
bool mFreeToUse = true;
|
||||
nsresult mPrimaryStreamStatus = NS_OK;
|
||||
|
||||
RefPtr<ConnectionEntry> mEnt;
|
||||
nsCOMPtr<nsITimer> mSynTimer;
|
||||
TransportSetup mBackupTransport;
|
||||
|
||||
bool mIsHttp3;
|
||||
|
||||
bool mSkipDnsResolution = false;
|
||||
bool mProxyNotTransparent = false;
|
||||
bool mProxyTransparentResolvesHost = false;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(DnsAndConnectSocket, NS_DNSANDCONNECTSOCKET_IID)
|
||||
|
@ -61,7 +61,7 @@ class HttpConnectionBase : public nsSupportsWeakReference {
|
||||
[[nodiscard]] virtual nsresult Init(
|
||||
nsHttpConnectionInfo* info, uint16_t maxHangTime, nsISocketTransport*,
|
||||
nsIAsyncInputStream*, nsIAsyncOutputStream*, bool connectedTransport,
|
||||
nsIInterfaceRequestor*, PRIntervalTime) = 0;
|
||||
nsresult status, nsIInterfaceRequestor*, PRIntervalTime) = 0;
|
||||
|
||||
// Activate causes the given transaction to be processed on this
|
||||
// connection. It fails if there is already an existing transaction unless
|
||||
@ -161,6 +161,7 @@ class HttpConnectionBase : public nsSupportsWeakReference {
|
||||
|
||||
nsTArray<HttpTrafficCategory> mTrafficCategory;
|
||||
PRIntervalTime mRtt;
|
||||
nsresult mErrorBeforeConnect = NS_OK;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(HttpConnectionBase, HTTPCONNECTIONBASE_IID)
|
||||
@ -168,7 +169,7 @@ NS_DEFINE_STATIC_IID_ACCESSOR(HttpConnectionBase, HTTPCONNECTIONBASE_IID)
|
||||
#define NS_DECL_HTTPCONNECTIONBASE \
|
||||
[[nodiscard]] nsresult Init( \
|
||||
nsHttpConnectionInfo*, uint16_t, nsISocketTransport*, \
|
||||
nsIAsyncInputStream*, nsIAsyncOutputStream*, bool, \
|
||||
nsIAsyncInputStream*, nsIAsyncOutputStream*, bool, nsresult, \
|
||||
nsIInterfaceRequestor*, PRIntervalTime) override; \
|
||||
[[nodiscard]] nsresult Activate(nsAHttpTransaction*, uint32_t, int32_t) \
|
||||
override; \
|
||||
|
@ -90,11 +90,12 @@ HttpConnectionUDP::~HttpConnectionUDP() {
|
||||
nsresult HttpConnectionUDP::Init(
|
||||
nsHttpConnectionInfo* info, uint16_t maxHangTime,
|
||||
nsISocketTransport* transport, nsIAsyncInputStream* instream,
|
||||
nsIAsyncOutputStream* outstream, bool connectedTransport,
|
||||
nsIAsyncOutputStream* outstream, bool connectedTransport, nsresult status,
|
||||
nsIInterfaceRequestor* callbacks, PRIntervalTime rtt) {
|
||||
LOG1(("HttpConnectionUDP::Init this=%p sockettransport=%p", this, transport));
|
||||
NS_ENSURE_ARG_POINTER(info);
|
||||
NS_ENSURE_TRUE(!mConnInfo, NS_ERROR_ALREADY_INITIALIZED);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(status) || !connectedTransport);
|
||||
|
||||
mConnectedTransport = connectedTransport;
|
||||
mConnInfo = info;
|
||||
@ -103,29 +104,38 @@ nsresult HttpConnectionUDP::Init(
|
||||
mLastWriteTime = mLastReadTime = PR_IntervalNow();
|
||||
mRtt = rtt;
|
||||
|
||||
mSocketTransport = transport;
|
||||
mSocketIn = instream;
|
||||
mSocketOut = outstream;
|
||||
mErrorBeforeConnect = status;
|
||||
if (NS_FAILED(mErrorBeforeConnect)) {
|
||||
MOZ_ASSERT(!mConnectedTransport);
|
||||
// See explanation for non-strictness of this operation in
|
||||
// SetSecurityCallbacks.
|
||||
mCallbacks = new nsMainThreadPtrHolder<nsIInterfaceRequestor>(
|
||||
"HttpConnectionUDP::mCallbacks", callbacks, false);
|
||||
} else {
|
||||
mSocketTransport = transport;
|
||||
mSocketIn = instream;
|
||||
mSocketOut = outstream;
|
||||
|
||||
MOZ_ASSERT(mConnInfo->IsHttp3());
|
||||
mHttp3Session = new Http3Session();
|
||||
nsresult rv = mHttp3Session->Init(mConnInfo, mSocketTransport, this);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(
|
||||
("HttpConnectionUDP::Init mHttp3Session->Init failed "
|
||||
"[this=%p rv=%x]\n",
|
||||
this, static_cast<uint32_t>(rv)));
|
||||
return rv;
|
||||
MOZ_ASSERT(mConnInfo->IsHttp3());
|
||||
mHttp3Session = new Http3Session();
|
||||
nsresult rv = mHttp3Session->Init(mConnInfo, mSocketTransport, this);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(
|
||||
("HttpConnectionUDP::Init mHttp3Session->Init failed "
|
||||
"[this=%p rv=%x]\n",
|
||||
this, static_cast<uint32_t>(rv)));
|
||||
return rv;
|
||||
}
|
||||
|
||||
// See explanation for non-strictness of this operation in
|
||||
// SetSecurityCallbacks.
|
||||
mCallbacks = new nsMainThreadPtrHolder<nsIInterfaceRequestor>(
|
||||
"HttpConnectionUDP::mCallbacks", callbacks, false);
|
||||
|
||||
mSocketTransport->SetEventSink(this, nullptr);
|
||||
mSocketTransport->SetSecurityCallbacks(this);
|
||||
}
|
||||
|
||||
// See explanation for non-strictness of this operation in
|
||||
// SetSecurityCallbacks.
|
||||
mCallbacks = new nsMainThreadPtrHolder<nsIInterfaceRequestor>(
|
||||
"HttpConnectionUDP::mCallbacks", callbacks, false);
|
||||
|
||||
mSocketTransport->SetEventSink(this, nullptr);
|
||||
mSocketTransport->SetSecurityCallbacks(this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -140,7 +150,7 @@ nsresult HttpConnectionUDP::Activate(nsAHttpTransaction* trans, uint32_t caps,
|
||||
// For QUIC we have HttpConnecitonUDP before the actual connection
|
||||
// has been establish so wait for TLS handshake to be finished before
|
||||
// we mark the connection 'experienced'.
|
||||
if (!mExperienced && mHttp3Session->IsConnected()) {
|
||||
if (!mExperienced && mHttp3Session && mHttp3Session->IsConnected()) {
|
||||
mExperienced = true;
|
||||
}
|
||||
if (mBootstrappedTimingsSet) {
|
||||
@ -164,6 +174,12 @@ nsresult HttpConnectionUDP::Activate(nsAHttpTransaction* trans, uint32_t caps,
|
||||
// Connection failures are Activated() just like regular transacions.
|
||||
// If we don't have a confirmation of a connected socket then test it
|
||||
// with a write() to get relevant error code.
|
||||
if (NS_FAILED(mErrorBeforeConnect)) {
|
||||
CloseTransaction(nullptr, mErrorBeforeConnect);
|
||||
trans->Close(mErrorBeforeConnect);
|
||||
gHttpHandler->ExcludeHttp3(mConnInfo);
|
||||
return mErrorBeforeConnect;
|
||||
}
|
||||
if (!mConnectedTransport) {
|
||||
uint32_t count;
|
||||
nsresult rv = NS_OK;
|
||||
@ -175,6 +191,7 @@ nsresult HttpConnectionUDP::Activate(nsAHttpTransaction* trans, uint32_t caps,
|
||||
this, static_cast<uint32_t>(rv)));
|
||||
mSocketOut->AsyncWait(nullptr, 0, 0, nullptr);
|
||||
CloseTransaction(mHttp3Session, rv);
|
||||
gHttpHandler->ExcludeHttp3(mConnInfo);
|
||||
trans->Close(rv);
|
||||
return rv;
|
||||
}
|
||||
|
@ -1182,7 +1182,7 @@ bool SpdyConnectTransaction::MapStreamToHttpConnection(
|
||||
TimeDuration rtt = TimeStamp::Now() - mTimestampSyn;
|
||||
DebugOnly<nsresult> rv = mTunneledConn->Init(
|
||||
aConnInfo, gHttpHandler->ConnMgr()->MaxRequestDelay(), mTunnelTransport,
|
||||
mTunnelStreamIn, mTunnelStreamOut, true, callbacks,
|
||||
mTunnelStreamIn, mTunnelStreamOut, true, NS_OK, callbacks,
|
||||
PR_MillisecondsToInterval(static_cast<uint32_t>(rtt.ToMilliseconds())));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (mForcePlainText) {
|
||||
@ -2147,6 +2147,11 @@ SocketTransportShim::SetQoSBits(uint8_t aQoSBits) {
|
||||
return mWrapped->SetQoSBits(aQoSBits);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SocketTransportShim::GetRetryDnsIfPossible(bool* aRetry) {
|
||||
return mWrapped->GetRetryDnsIfPossible(aRetry);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(TLSFilterTransaction, nsITimerCallback, nsINamed)
|
||||
NS_IMPL_ISUPPORTS(SocketTransportShim, nsISocketTransport, nsITransport)
|
||||
NS_IMPL_ISUPPORTS(InputStreamShim, nsIInputStream, nsIAsyncInputStream)
|
||||
|
@ -169,11 +169,12 @@ nsHttpConnection::~nsHttpConnection() {
|
||||
nsresult nsHttpConnection::Init(
|
||||
nsHttpConnectionInfo* info, uint16_t maxHangTime,
|
||||
nsISocketTransport* transport, nsIAsyncInputStream* instream,
|
||||
nsIAsyncOutputStream* outstream, bool connectedTransport,
|
||||
nsIAsyncOutputStream* outstream, bool connectedTransport, nsresult status,
|
||||
nsIInterfaceRequestor* callbacks, PRIntervalTime rtt) {
|
||||
LOG1(("nsHttpConnection::Init this=%p sockettransport=%p", this, transport));
|
||||
NS_ENSURE_ARG_POINTER(info);
|
||||
NS_ENSURE_TRUE(!mConnInfo, NS_ERROR_ALREADY_INITIALIZED);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(status) || !connectedTransport);
|
||||
|
||||
mConnectedTransport = connectedTransport;
|
||||
mConnInfo = info;
|
||||
@ -192,8 +193,11 @@ nsresult nsHttpConnection::Init(
|
||||
mCallbacks = new nsMainThreadPtrHolder<nsIInterfaceRequestor>(
|
||||
"nsHttpConnection::mCallbacks", callbacks, false);
|
||||
|
||||
mSocketTransport->SetEventSink(this, nullptr);
|
||||
mSocketTransport->SetSecurityCallbacks(this);
|
||||
mErrorBeforeConnect = status;
|
||||
if (NS_SUCCEEDED(mErrorBeforeConnect)) {
|
||||
mSocketTransport->SetEventSink(this, nullptr);
|
||||
mSocketTransport->SetSecurityCallbacks(this);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -747,15 +751,18 @@ nsresult nsHttpConnection::Activate(nsAHttpTransaction* trans, uint32_t caps,
|
||||
// Connection failures are Activated() just like regular transacions.
|
||||
// If we don't have a confirmation of a connected socket then test it
|
||||
// with a write() to get relevant error code.
|
||||
if (NS_FAILED(mErrorBeforeConnect)) {
|
||||
mSocketOutCondition = mErrorBeforeConnect;
|
||||
mTransaction = trans;
|
||||
CloseTransaction(mTransaction, mSocketOutCondition);
|
||||
return mSocketOutCondition;
|
||||
}
|
||||
|
||||
if (!mConnectedTransport) {
|
||||
if (NS_FAILED(mErrorBeforeConnect)) {
|
||||
mSocketOutCondition = mErrorBeforeConnect;
|
||||
} else {
|
||||
uint32_t count;
|
||||
mSocketOutCondition = NS_ERROR_FAILURE;
|
||||
if (mSocketOut) {
|
||||
mSocketOutCondition = mSocketOut->Write("", 0, &count);
|
||||
}
|
||||
uint32_t count;
|
||||
mSocketOutCondition = NS_ERROR_FAILURE;
|
||||
if (mSocketOut) {
|
||||
mSocketOutCondition = mSocketOut->Write("", 0, &count);
|
||||
}
|
||||
if (NS_FAILED(mSocketOutCondition) &&
|
||||
mSocketOutCondition != NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
|
@ -1504,7 +1504,6 @@ nsresult nsHttpConnectionMgr::DispatchTransaction(ConnectionEntry* ent,
|
||||
"Connection host = %s\n",
|
||||
trans->ConnectionInfo()->Origin(), conn->ConnectionInfo()->Origin()));
|
||||
rv = conn->Activate(trans, caps, priority);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "SPDY Cannot Fail Dispatch");
|
||||
if (NS_SUCCEEDED(rv) && !trans->GetPendingTime().IsNull()) {
|
||||
if (conn->UsingSpdy()) {
|
||||
AccumulateTimeDelta(Telemetry::TRANSACTION_WAIT_TIME_SPDY,
|
||||
@ -1732,7 +1731,7 @@ nsresult nsHttpConnectionMgr::CreateTransport(
|
||||
// The socket stream holds the reference to the half open
|
||||
// socket - so if the stream fails to init the half open
|
||||
// will go away.
|
||||
nsresult rv = sock->SetupPrimaryStreams();
|
||||
nsresult rv = sock->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (pendingTransInfo) {
|
||||
|
@ -131,7 +131,7 @@ TEST(TestBind, MainTest)
|
||||
for (int32_t tried = 0; tried < 100; tried++) {
|
||||
nsCOMPtr<nsISocketTransport> client;
|
||||
rv = sts->CreateTransport(nsTArray<nsCString>(), "127.0.0.1"_ns, serverPort,
|
||||
nullptr, getter_AddRefs(client));
|
||||
nullptr, nullptr, getter_AddRefs(client));
|
||||
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
||||
|
||||
// Bind to a port. It's possible that we are binding to a port that is
|
||||
|
@ -443,7 +443,13 @@ function runRawTests(testArray, done, beforeTestCallback) {
|
||||
|
||||
var rawTest = testArray[testIndex];
|
||||
|
||||
var transport = sts.createTransport([], rawTest.host, rawTest.port, null);
|
||||
var transport = sts.createTransport(
|
||||
[],
|
||||
rawTest.host,
|
||||
rawTest.port,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
var inStream = transport.openInputStream(0, 0, 0);
|
||||
var outStream = transport.openOutputStream(0, 0, 0);
|
||||
|
@ -59,7 +59,7 @@ async function launchConnection(
|
||||
-1,
|
||||
null
|
||||
);
|
||||
let trans = sts.createTransport([], dest_host, dest_port, pi);
|
||||
let trans = sts.createTransport([], dest_host, dest_port, pi, null);
|
||||
let input = trans.openInputStream(0, 0, 0);
|
||||
let output = trans.openOutputStream(0, 0, 0);
|
||||
input = await waitForStream(input, Ci.nsIAsyncInputStream);
|
||||
|
@ -66,6 +66,7 @@ add_test(function test_sockets() {
|
||||
[],
|
||||
"127.0.0.1",
|
||||
gServerSocket.port,
|
||||
null,
|
||||
null
|
||||
);
|
||||
let listener = {
|
||||
|
@ -182,6 +182,7 @@ function testIpv4() {
|
||||
[],
|
||||
"127.0.0.1",
|
||||
serv.port,
|
||||
null,
|
||||
null
|
||||
);
|
||||
/*
|
||||
|
@ -187,7 +187,7 @@ function test_hostnames_resolving_to_addresses(host, next) {
|
||||
Ci.nsISocketTransportService
|
||||
);
|
||||
Assert.notEqual(typeof sts, undefined);
|
||||
var transport = sts.createTransport([], host, 80, null);
|
||||
var transport = sts.createTransport([], host, 80, null, null);
|
||||
Assert.notEqual(typeof transport, undefined);
|
||||
|
||||
transport.connectionFlags = Ci.nsISocketTransport.DISABLE_RFC1918;
|
||||
@ -269,7 +269,7 @@ function test_proxies(proxyHost, next) {
|
||||
var proxyInfo = pps.newProxyInfo("http", proxyHost, 8080, "", "", 0, 1, null);
|
||||
Assert.notEqual(typeof proxyInfo, undefined);
|
||||
|
||||
var transport = sts.createTransport([], "dummyHost", 80, proxyInfo);
|
||||
var transport = sts.createTransport([], "dummyHost", 80, proxyInfo, null);
|
||||
Assert.notEqual(typeof transport, undefined);
|
||||
|
||||
transport.connectionFlags = Ci.nsISocketTransport.DISABLE_RFC1918;
|
||||
|
@ -135,6 +135,7 @@ function startClient(port, cert, expectingAlert, tlsVersion) {
|
||||
["ssl"],
|
||||
"127.0.0.1",
|
||||
port,
|
||||
null,
|
||||
null
|
||||
);
|
||||
let input;
|
||||
|
@ -96,6 +96,7 @@ function startClient(port) {
|
||||
["ssl"],
|
||||
"127.0.0.1",
|
||||
port,
|
||||
null,
|
||||
null
|
||||
);
|
||||
let input;
|
||||
|
@ -523,7 +523,13 @@ async function asyncConnectTo(
|
||||
let sts = Cc["@mozilla.org/network/socket-transport-service;1"].getService(
|
||||
Ci.nsISocketTransportService
|
||||
);
|
||||
this.transport = sts.createTransport(["ssl"], host, REMOTE_PORT, null);
|
||||
this.transport = sts.createTransport(
|
||||
["ssl"],
|
||||
host,
|
||||
REMOTE_PORT,
|
||||
null,
|
||||
null
|
||||
);
|
||||
if (aEchConfig) {
|
||||
this.transport.setEchConfig(atob(aEchConfig));
|
||||
}
|
||||
|
@ -390,7 +390,7 @@ class SocksTestClient {
|
||||
null
|
||||
);
|
||||
|
||||
this.trans = sts.createTransport([], dest.host, dest.port, pi);
|
||||
this.trans = sts.createTransport([], dest.host, dest.port, pi, null);
|
||||
this.input = this.trans.openInputStream(
|
||||
Ci.nsITransport.OPEN_BLOCKING,
|
||||
0,
|
||||
|
Loading…
Reference in New Issue
Block a user