HTTPSRecordResolver.cpp (6125B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 // HttpLog.h should generally be included first 7 #include "HttpLog.h" 8 9 #include "HTTPSRecordResolver.h" 10 #include "mozilla/Components.h" 11 #include "mozilla/StaticPrefs_network.h" 12 #include "nsIDNSByTypeRecord.h" 13 #include "nsIDNSAdditionalInfo.h" 14 #include "nsIDNSService.h" 15 #include "nsHttpConnectionInfo.h" 16 #include "nsNetCID.h" 17 #include "nsAHttpTransaction.h" 18 #include "nsServiceManagerUtils.h" 19 20 namespace mozilla { 21 namespace net { 22 23 NS_IMPL_ISUPPORTS(HTTPSRecordResolver, nsIDNSListener) 24 25 HTTPSRecordResolver::HTTPSRecordResolver(nsAHttpTransaction* aTransaction) 26 : mTransaction(aTransaction), mConnInfo(aTransaction->ConnectionInfo()) {} 27 28 HTTPSRecordResolver::~HTTPSRecordResolver() = default; 29 30 nsresult HTTPSRecordResolver::FetchHTTPSRRInternal( 31 nsIEventTarget* aTarget, nsICancelable** aDNSRequest) { 32 NS_ENSURE_ARG_POINTER(aTarget); 33 34 // Only fetch HTTPS RR for https. 35 if (!mConnInfo->FirstHopSSL()) { 36 return NS_ERROR_FAILURE; 37 } 38 39 nsCOMPtr<nsIDNSService> dns = mozilla::components::DNS::Service(); 40 if (!dns) { 41 return NS_ERROR_NOT_AVAILABLE; 42 } 43 44 nsIDNSService::DNSFlags flags = 45 nsIDNSService::GetFlagsFromTRRMode(mConnInfo->GetTRRMode()); 46 if (mTransaction->Caps() & NS_HTTP_REFRESH_DNS) { 47 flags |= nsIDNSService::RESOLVE_BYPASS_CACHE; 48 } 49 50 nsCOMPtr<nsIDNSAdditionalInfo> info; 51 if (mConnInfo->OriginPort() != NS_HTTPS_DEFAULT_PORT) { 52 dns->NewAdditionalInfo(""_ns, mConnInfo->OriginPort(), 53 getter_AddRefs(info)); 54 } 55 56 MutexAutoLock lock(mMutex); 57 58 nsresult rv = dns->AsyncResolveNative( 59 mConnInfo->GetOrigin(), nsIDNSService::RESOLVE_TYPE_HTTPSSVC, flags, info, 60 this, aTarget, mConnInfo->GetOriginAttributes(), 61 getter_AddRefs(mHTTPSRecordRequest)); 62 63 if (NS_FAILED(rv)) { 64 return rv; 65 } 66 67 nsCOMPtr<nsICancelable> request = mHTTPSRecordRequest; 68 request.forget(aDNSRequest); 69 70 if (!StaticPrefs::network_dns_https_rr_check_record_with_cname()) { 71 return rv; 72 } 73 74 rv = dns->AsyncResolveNative( 75 mConnInfo->GetOrigin(), nsIDNSService::RESOLVE_TYPE_DEFAULT, 76 flags | nsIDNSService::RESOLVE_CANONICAL_NAME, nullptr, this, aTarget, 77 mConnInfo->GetOriginAttributes(), getter_AddRefs(mCnameRequest)); 78 return rv; 79 } 80 81 NS_IMETHODIMP HTTPSRecordResolver::OnLookupComplete(nsICancelable* aRequest, 82 nsIDNSRecord* aRecord, 83 nsresult aStatus) { 84 MutexAutoLock lock(mMutex); 85 if (!mTransaction || mDone) { 86 // The transaction is not interesed in a response anymore. 87 mCnameRequest = nullptr; 88 mHTTPSRecordRequest = nullptr; 89 return NS_OK; 90 } 91 92 if (aRequest == mHTTPSRecordRequest) { 93 nsCOMPtr<nsIDNSHTTPSSVCRecord> record = do_QueryInterface(aRecord); 94 mHTTPSRecordRequest = nullptr; 95 if (!record || NS_FAILED(aStatus)) { 96 // When failed, we don't want to wait for the CNAME. 97 mCnameRequest = nullptr; 98 MutexAutoUnlock unlock(mMutex); 99 return InvokeCallback(); 100 } 101 102 mHTTPSRecord = record; 103 104 // Waiting for the address record. 105 if (mCnameRequest) { 106 return NS_OK; 107 } 108 109 MutexAutoUnlock unlock(mMutex); 110 return InvokeCallback(); 111 } 112 113 // Having mCnameRequest indicates that we are interested in the address 114 // record. 115 if (mCnameRequest && aRequest == mCnameRequest) { 116 nsCOMPtr<nsIDNSAddrRecord> addrRecord = do_QueryInterface(aRecord); 117 mCnameRequest = nullptr; 118 if (!addrRecord || NS_FAILED(aStatus)) { 119 // If we are still waiting for HTTPS RR, don't invoke the callback. 120 if (mHTTPSRecordRequest) { 121 return NS_OK; 122 } 123 124 MutexAutoUnlock unlock(mMutex); 125 return InvokeCallback(); 126 } 127 128 mAddrRecord = addrRecord; 129 // Waiting for the HTTPS record. 130 if (mHTTPSRecordRequest) { 131 return NS_OK; 132 } 133 134 MutexAutoUnlock unlock(mMutex); 135 return InvokeCallback(); 136 } 137 138 return NS_OK; 139 } 140 141 nsresult HTTPSRecordResolver::InvokeCallback() { 142 MOZ_ASSERT(!mDone); 143 144 mDone = true; 145 if (!mHTTPSRecord) { 146 return mTransaction->OnHTTPSRRAvailable(nullptr, nullptr, ""_ns); 147 } 148 149 nsCString cname; 150 if (mAddrRecord) { 151 (void)mAddrRecord->GetCanonicalName(cname); 152 } 153 154 // Make sure we use the updated caps from the transaction. 155 uint32_t caps = mTransaction->Caps(); 156 nsCOMPtr<nsISVCBRecord> svcbRecord; 157 if (NS_FAILED(mHTTPSRecord->GetServiceModeRecordWithCname( 158 caps & NS_HTTP_DISALLOW_SPDY, caps & NS_HTTP_DISALLOW_HTTP3, cname, 159 getter_AddRefs(svcbRecord)))) { 160 return mTransaction->OnHTTPSRRAvailable(mHTTPSRecord, nullptr, cname); 161 } 162 163 return mTransaction->OnHTTPSRRAvailable(mHTTPSRecord, svcbRecord, cname); 164 } 165 166 void HTTPSRecordResolver::PrefetchAddrRecord(const nsACString& aTargetName, 167 bool aRefreshDNS) { 168 MOZ_ASSERT(mTransaction); 169 nsCOMPtr<nsIDNSService> dns = mozilla::components::DNS::Service(); 170 if (!dns) { 171 return; 172 } 173 174 nsIDNSService::DNSFlags flags = nsIDNSService::GetFlagsFromTRRMode( 175 mTransaction->ConnectionInfo()->GetTRRMode()); 176 if (aRefreshDNS) { 177 flags |= nsIDNSService::RESOLVE_BYPASS_CACHE; 178 } 179 180 nsCOMPtr<nsICancelable> tmpOutstanding; 181 182 (void)dns->AsyncResolveNative( 183 aTargetName, nsIDNSService::RESOLVE_TYPE_DEFAULT, 184 flags | nsIDNSService::RESOLVE_SPECULATE, nullptr, this, 185 GetCurrentSerialEventTarget(), 186 mTransaction->ConnectionInfo()->GetOriginAttributes(), 187 getter_AddRefs(tmpOutstanding)); 188 } 189 190 void HTTPSRecordResolver::Close() { 191 mTransaction = nullptr; 192 MutexAutoLock lock(mMutex); 193 if (mCnameRequest) { 194 mCnameRequest->Cancel(NS_ERROR_ABORT); 195 mCnameRequest = nullptr; 196 } 197 if (mHTTPSRecordRequest) { 198 mHTTPSRecordRequest->Cancel(NS_ERROR_ABORT); 199 mHTTPSRecordRequest = nullptr; 200 } 201 } 202 203 } // namespace net 204 } // namespace mozilla