tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }