nsDNSPrefetch.cpp (5134B)
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 #include "nsDNSPrefetch.h" 7 #include "nsCOMPtr.h" 8 #include "nsString.h" 9 #include "nsThreadUtils.h" 10 11 #include "nsIDNSAdditionalInfo.h" 12 #include "nsIDNSListener.h" 13 #include "nsIDNSService.h" 14 #include "nsIDNSByTypeRecord.h" 15 #include "nsICancelable.h" 16 #include "nsIURI.h" 17 #include "mozilla/Preferences.h" 18 19 static mozilla::StaticRefPtr<nsIDNSService> sDNSService; 20 21 nsresult nsDNSPrefetch::Initialize(nsIDNSService* aDNSService) { 22 MOZ_ASSERT(NS_IsMainThread()); 23 24 sDNSService = aDNSService; 25 return NS_OK; 26 } 27 28 nsresult nsDNSPrefetch::Shutdown() { 29 sDNSService = nullptr; 30 return NS_OK; 31 } 32 33 nsDNSPrefetch::nsDNSPrefetch(nsIURI* aURI, 34 mozilla::OriginAttributes& aOriginAttributes, 35 nsIRequest::TRRMode aTRRMode, 36 nsIDNSListener* aListener, bool storeTiming) 37 : mOriginAttributes(aOriginAttributes), 38 mStoreTiming(storeTiming), 39 mTRRMode(aTRRMode), 40 mListener(do_GetWeakReference(aListener)) { 41 aURI->GetAsciiHost(mHostname); 42 aURI->GetPort(&mPort); 43 } 44 45 nsDNSPrefetch::nsDNSPrefetch(nsIURI* aURI, 46 mozilla::OriginAttributes& aOriginAttributes, 47 nsIRequest::TRRMode aTRRMode) 48 : mOriginAttributes(aOriginAttributes), 49 mStoreTiming(false), 50 mTRRMode(aTRRMode), 51 mListener(nullptr) { 52 aURI->GetAsciiHost(mHostname); 53 } 54 55 nsresult nsDNSPrefetch::Prefetch(nsIDNSService::DNSFlags flags) { 56 if (mHostname.IsEmpty()) return NS_ERROR_NOT_AVAILABLE; 57 58 if (!sDNSService) return NS_ERROR_NOT_AVAILABLE; 59 60 nsCOMPtr<nsICancelable> tmpOutstanding; 61 62 if (mStoreTiming) mStartTimestamp = mozilla::TimeStamp::Now(); 63 // If AsyncResolve fails, for example because prefetching is disabled, 64 // then our timing will be useless. However, in such a case, 65 // mEndTimestamp will be a null timestamp and callers should check 66 // TimingsValid() before using the timing. 67 nsCOMPtr<nsIEventTarget> target = mozilla::GetCurrentSerialEventTarget(); 68 69 flags |= nsIDNSService::GetFlagsFromTRRMode(mTRRMode); 70 71 return sDNSService->AsyncResolveNative( 72 mHostname, nsIDNSService::RESOLVE_TYPE_DEFAULT, 73 flags | nsIDNSService::RESOLVE_SPECULATE, nullptr, this, target, 74 mOriginAttributes, getter_AddRefs(tmpOutstanding)); 75 } 76 77 nsresult nsDNSPrefetch::PrefetchLow(nsIDNSService::DNSFlags aFlags) { 78 return Prefetch(nsIDNSService::RESOLVE_PRIORITY_LOW | aFlags); 79 } 80 81 nsresult nsDNSPrefetch::PrefetchMedium(nsIDNSService::DNSFlags aFlags) { 82 return Prefetch(nsIDNSService::RESOLVE_PRIORITY_MEDIUM | aFlags); 83 } 84 85 nsresult nsDNSPrefetch::PrefetchHigh(nsIDNSService::DNSFlags aFlags) { 86 return Prefetch(aFlags); 87 } 88 89 namespace { 90 91 class HTTPSRRListener final : public nsIDNSListener { 92 public: 93 NS_DECL_THREADSAFE_ISUPPORTS 94 NS_DECL_NSIDNSLISTENER 95 96 explicit HTTPSRRListener( 97 std::function<void(nsIDNSHTTPSSVCRecord*)>&& aCallback) 98 : mResultCallback(std::move(aCallback)) {} 99 100 private: 101 ~HTTPSRRListener() = default; 102 std::function<void(nsIDNSHTTPSSVCRecord*)> mResultCallback; 103 }; 104 105 NS_IMPL_ISUPPORTS(HTTPSRRListener, nsIDNSListener) 106 107 NS_IMETHODIMP 108 HTTPSRRListener::OnLookupComplete(nsICancelable* aRequest, nsIDNSRecord* aRec, 109 nsresult aStatus) { 110 if (NS_FAILED(aStatus)) { 111 mResultCallback(nullptr); 112 return NS_OK; 113 } 114 115 nsCOMPtr<nsIDNSHTTPSSVCRecord> httpsRecord = do_QueryInterface(aRec); 116 mResultCallback(httpsRecord); 117 return NS_OK; 118 } 119 120 }; // namespace 121 122 nsresult nsDNSPrefetch::FetchHTTPSSVC( 123 bool aRefreshDNS, bool aPrefetch, 124 std::function<void(nsIDNSHTTPSSVCRecord*)>&& aCallback) { 125 if (!sDNSService) { 126 return NS_ERROR_NOT_AVAILABLE; 127 } 128 129 nsCOMPtr<nsIEventTarget> target = mozilla::GetCurrentSerialEventTarget(); 130 nsIDNSService::DNSFlags flags = nsIDNSService::GetFlagsFromTRRMode(mTRRMode); 131 if (aRefreshDNS) { 132 flags |= nsIDNSService::RESOLVE_BYPASS_CACHE; 133 } 134 if (aPrefetch) { 135 flags |= nsIDNSService::RESOLVE_SPECULATE; 136 } 137 138 nsCOMPtr<nsICancelable> tmpOutstanding; 139 nsCOMPtr<nsIDNSListener> listener = new HTTPSRRListener(std::move(aCallback)); 140 nsCOMPtr<nsIDNSAdditionalInfo> info; 141 if (mPort != -1) { 142 sDNSService->NewAdditionalInfo(""_ns, mPort, getter_AddRefs(info)); 143 } 144 return sDNSService->AsyncResolveNative( 145 mHostname, nsIDNSService::RESOLVE_TYPE_HTTPSSVC, flags, info, listener, 146 target, mOriginAttributes, getter_AddRefs(tmpOutstanding)); 147 } 148 149 NS_IMPL_ISUPPORTS(nsDNSPrefetch, nsIDNSListener) 150 151 NS_IMETHODIMP 152 nsDNSPrefetch::OnLookupComplete(nsICancelable* request, nsIDNSRecord* rec, 153 nsresult status) { 154 if (mStoreTiming) { 155 mEndTimestamp = mozilla::TimeStamp::Now(); 156 } 157 nsCOMPtr<nsIDNSListener> listener = do_QueryReferent(mListener); 158 if (listener) { 159 listener->OnLookupComplete(request, rec, status); 160 } 161 162 return NS_OK; 163 }