Source code

Revision control

Other Tools

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 "nsIDNSListener.h"
12
#include "nsIDNSService.h"
13
#include "nsICancelable.h"
14
#include "nsIURI.h"
15
#include "mozilla/Preferences.h"
16
17
static nsIDNSService* sDNSService = nullptr;
18
static bool sESNIEnabled = false;
19
20
nsresult nsDNSPrefetch::Initialize(nsIDNSService* aDNSService) {
21
NS_IF_RELEASE(sDNSService);
22
sDNSService = aDNSService;
23
NS_IF_ADDREF(sDNSService);
24
mozilla::Preferences::AddBoolVarCache(&sESNIEnabled,
25
"network.security.esni.enabled");
26
return NS_OK;
27
}
28
29
nsresult nsDNSPrefetch::Shutdown() {
30
NS_IF_RELEASE(sDNSService);
31
return NS_OK;
32
}
33
34
nsDNSPrefetch::nsDNSPrefetch(nsIURI* aURI,
35
mozilla::OriginAttributes& aOriginAttributes,
36
nsIDNSListener* aListener, bool storeTiming)
37
: mOriginAttributes(aOriginAttributes),
38
mStoreTiming(storeTiming),
39
mListener(do_GetWeakReference(aListener)) {
40
aURI->GetAsciiHost(mHostname);
41
mIsHttps = false;
42
aURI->SchemeIs("https", &mIsHttps);
43
}
44
45
nsresult nsDNSPrefetch::Prefetch(uint16_t flags) {
46
// This can work properly only if this call is on the main thread.
47
// Curenlty we use nsDNSPrefetch only in nsHttpChannel which will call
48
// PrefetchHigh() from the main thread. Let's add assertion to catch
49
// if things change.
50
MOZ_ASSERT(NS_IsMainThread(), "Expecting DNS callback on main thread.");
51
52
if (mHostname.IsEmpty()) return NS_ERROR_NOT_AVAILABLE;
53
54
if (!sDNSService) return NS_ERROR_NOT_AVAILABLE;
55
56
nsCOMPtr<nsICancelable> tmpOutstanding;
57
58
if (mStoreTiming) mStartTimestamp = mozilla::TimeStamp::Now();
59
// If AsyncResolve fails, for example because prefetching is disabled,
60
// then our timing will be useless. However, in such a case,
61
// mEndTimestamp will be a null timestamp and callers should check
62
// TimingsValid() before using the timing.
63
nsCOMPtr<nsIEventTarget> main = mozilla::GetMainThreadEventTarget();
64
65
nsresult rv = sDNSService->AsyncResolveNative(
66
mHostname, flags | nsIDNSService::RESOLVE_SPECULATE, this, main,
67
mOriginAttributes, getter_AddRefs(tmpOutstanding));
68
if (NS_FAILED(rv)) {
69
return rv;
70
}
71
72
// Fetch esni keys if needed.
73
if (sESNIEnabled && mIsHttps) {
74
nsAutoCString esniHost;
75
esniHost.Append("_esni.");
76
esniHost.Append(mHostname);
77
sDNSService->AsyncResolveByTypeNative(
78
esniHost, nsIDNSService::RESOLVE_TYPE_TXT,
79
flags | nsIDNSService::RESOLVE_SPECULATE, this, main, mOriginAttributes,
80
getter_AddRefs(tmpOutstanding));
81
}
82
return NS_OK;
83
}
84
85
nsresult nsDNSPrefetch::PrefetchLow(bool refreshDNS) {
86
return Prefetch(nsIDNSService::RESOLVE_PRIORITY_LOW |
87
(refreshDNS ? nsIDNSService::RESOLVE_BYPASS_CACHE : 0));
88
}
89
90
nsresult nsDNSPrefetch::PrefetchMedium(bool refreshDNS) {
91
return Prefetch(nsIDNSService::RESOLVE_PRIORITY_MEDIUM |
92
(refreshDNS ? nsIDNSService::RESOLVE_BYPASS_CACHE : 0));
93
}
94
95
nsresult nsDNSPrefetch::PrefetchHigh(bool refreshDNS) {
96
return Prefetch(refreshDNS ? nsIDNSService::RESOLVE_BYPASS_CACHE : 0);
97
}
98
99
NS_IMPL_ISUPPORTS(nsDNSPrefetch, nsIDNSListener)
100
101
NS_IMETHODIMP
102
nsDNSPrefetch::OnLookupComplete(nsICancelable* request, nsIDNSRecord* rec,
103
nsresult status) {
104
MOZ_ASSERT(NS_IsMainThread(), "Expecting DNS callback on main thread.");
105
106
if (mStoreTiming) {
107
mEndTimestamp = mozilla::TimeStamp::Now();
108
}
109
nsCOMPtr<nsIDNSListener> listener = do_QueryReferent(mListener);
110
if (listener) {
111
listener->OnLookupComplete(request, rec, status);
112
}
113
return NS_OK;
114
}
115
116
NS_IMETHODIMP
117
nsDNSPrefetch::OnLookupByTypeComplete(nsICancelable* request,
118
nsIDNSByTypeRecord* res,
119
nsresult status) {
120
MOZ_ASSERT(NS_IsMainThread(), "Expecting DNS callback on main thread.");
121
122
if (mStoreTiming) {
123
mEndTimestamp = mozilla::TimeStamp::Now();
124
}
125
nsCOMPtr<nsIDNSListener> listener = do_QueryReferent(mListener);
126
if (listener) {
127
listener->OnLookupByTypeComplete(request, res, status);
128
}
129
return NS_OK;
130
}