|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "mozilla/net/ChildDNSService.h" |
|
6 #include "nsIDNSListener.h" |
|
7 #include "nsNetUtil.h" |
|
8 #include "nsIThread.h" |
|
9 #include "nsThreadUtils.h" |
|
10 #include "nsIXPConnect.h" |
|
11 #include "nsIPrefService.h" |
|
12 #include "nsIProtocolProxyService.h" |
|
13 #include "mozilla/net/NeckoChild.h" |
|
14 #include "mozilla/net/DNSRequestChild.h" |
|
15 #include "mozilla/net/DNSListenerProxy.h" |
|
16 |
|
17 namespace mozilla { |
|
18 namespace net { |
|
19 |
|
20 //----------------------------------------------------------------------------- |
|
21 // ChildDNSService |
|
22 //----------------------------------------------------------------------------- |
|
23 |
|
24 static ChildDNSService *gChildDNSService; |
|
25 static const char kPrefNameDisablePrefetch[] = "network.dns.disablePrefetch"; |
|
26 |
|
27 ChildDNSService* ChildDNSService::GetSingleton() |
|
28 { |
|
29 MOZ_ASSERT(IsNeckoChild()); |
|
30 |
|
31 if (!gChildDNSService) { |
|
32 gChildDNSService = new ChildDNSService(); |
|
33 } |
|
34 |
|
35 NS_ADDREF(gChildDNSService); |
|
36 return gChildDNSService; |
|
37 } |
|
38 |
|
39 NS_IMPL_ISUPPORTS(ChildDNSService, |
|
40 nsIDNSService, |
|
41 nsPIDNSService, |
|
42 nsIObserver) |
|
43 |
|
44 ChildDNSService::ChildDNSService() |
|
45 : mFirstTime(true) |
|
46 , mOffline(false) |
|
47 { |
|
48 MOZ_ASSERT(IsNeckoChild()); |
|
49 } |
|
50 |
|
51 ChildDNSService::~ChildDNSService() |
|
52 { |
|
53 |
|
54 } |
|
55 |
|
56 //----------------------------------------------------------------------------- |
|
57 // ChildDNSService::nsIDNSService |
|
58 //----------------------------------------------------------------------------- |
|
59 |
|
60 NS_IMETHODIMP |
|
61 ChildDNSService::AsyncResolve(const nsACString &hostname, |
|
62 uint32_t flags, |
|
63 nsIDNSListener *listener, |
|
64 nsIEventTarget *target_, |
|
65 nsICancelable **result) |
|
66 { |
|
67 NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE); |
|
68 |
|
69 if (mDisablePrefetch && (flags & RESOLVE_SPECULATE)) { |
|
70 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL; |
|
71 } |
|
72 |
|
73 // Support apps being 'offline' even if parent is not: avoids DNS traffic by |
|
74 // apps that have been told they are offline. |
|
75 if (mOffline) { |
|
76 flags |= RESOLVE_OFFLINE; |
|
77 } |
|
78 |
|
79 // make sure JS callers get notification on the main thread |
|
80 nsCOMPtr<nsIEventTarget> target = target_; |
|
81 nsCOMPtr<nsIXPConnectWrappedJS> wrappedListener = do_QueryInterface(listener); |
|
82 if (wrappedListener && !target) { |
|
83 nsCOMPtr<nsIThread> mainThread; |
|
84 NS_GetMainThread(getter_AddRefs(mainThread)); |
|
85 target = do_QueryInterface(mainThread); |
|
86 } |
|
87 if (target) { |
|
88 // Guarantee listener freed on main thread. Not sure we need this in child |
|
89 // (or in parent in nsDNSService.cpp) but doesn't hurt. |
|
90 listener = new DNSListenerProxy(listener, target); |
|
91 } |
|
92 |
|
93 nsRefPtr<DNSRequestChild> childReq = |
|
94 new DNSRequestChild(nsCString(hostname), flags, listener, target); |
|
95 |
|
96 childReq->StartRequest(); |
|
97 |
|
98 childReq.forget(result); |
|
99 return NS_OK; |
|
100 } |
|
101 |
|
102 NS_IMETHODIMP |
|
103 ChildDNSService::CancelAsyncResolve(const nsACString &aHostname, |
|
104 uint32_t aFlags, |
|
105 nsIDNSListener *aListener, |
|
106 nsresult aReason) |
|
107 { |
|
108 if (mDisablePrefetch && (aFlags & RESOLVE_SPECULATE)) { |
|
109 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL; |
|
110 } |
|
111 |
|
112 // TODO: keep a hashtable of pending requests, so we can obey cancel semantics |
|
113 // (call OnLookupComplete with aReason). Also possible we could send IPDL to |
|
114 // parent to cancel. |
|
115 return NS_ERROR_NOT_AVAILABLE; |
|
116 } |
|
117 |
|
118 NS_IMETHODIMP |
|
119 ChildDNSService::Resolve(const nsACString &hostname, |
|
120 uint32_t flags, |
|
121 nsIDNSRecord **result) |
|
122 { |
|
123 // not planning to ever support this, since sync IPDL is evil. |
|
124 return NS_ERROR_NOT_AVAILABLE; |
|
125 } |
|
126 |
|
127 NS_IMETHODIMP |
|
128 ChildDNSService::GetDNSCacheEntries(nsTArray<mozilla::net::DNSCacheEntries> *args) |
|
129 { |
|
130 // Only used by networking dashboard, so may not ever need this in child. |
|
131 // (and would provide a way to spy on what hosts other apps are connecting to, |
|
132 // unless we start keeping per-app DNS caches). |
|
133 return NS_ERROR_NOT_AVAILABLE; |
|
134 } |
|
135 |
|
136 NS_IMETHODIMP |
|
137 ChildDNSService::GetMyHostName(nsACString &result) |
|
138 { |
|
139 // TODO: get value from parent during PNecko construction? |
|
140 return NS_ERROR_NOT_AVAILABLE; |
|
141 } |
|
142 |
|
143 //----------------------------------------------------------------------------- |
|
144 // ChildDNSService::nsPIDNSService |
|
145 //----------------------------------------------------------------------------- |
|
146 |
|
147 nsresult |
|
148 ChildDNSService::Init() |
|
149 { |
|
150 // Disable prefetching either by explicit preference or if a manual proxy |
|
151 // is configured |
|
152 bool disablePrefetch = false; |
|
153 int proxyType = nsIProtocolProxyService::PROXYCONFIG_DIRECT; |
|
154 |
|
155 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); |
|
156 prefs->GetBoolPref(kPrefNameDisablePrefetch, &disablePrefetch); |
|
157 if (prefs) { |
|
158 prefs->GetIntPref("network.proxy.type", &proxyType); |
|
159 prefs->GetBoolPref(kPrefNameDisablePrefetch, &disablePrefetch); |
|
160 } |
|
161 |
|
162 if (mFirstTime) { |
|
163 mFirstTime = false; |
|
164 if (prefs) { |
|
165 prefs->AddObserver(kPrefNameDisablePrefetch, this, false); |
|
166 |
|
167 // Monitor these to see if there is a change in proxy configuration |
|
168 // If a manual proxy is in use, disable prefetch implicitly |
|
169 prefs->AddObserver("network.proxy.type", this, false); |
|
170 } |
|
171 } |
|
172 |
|
173 mDisablePrefetch = disablePrefetch || |
|
174 (proxyType == nsIProtocolProxyService::PROXYCONFIG_MANUAL); |
|
175 |
|
176 return NS_OK; |
|
177 } |
|
178 |
|
179 nsresult |
|
180 ChildDNSService::Shutdown() |
|
181 { |
|
182 return NS_OK; |
|
183 } |
|
184 |
|
185 NS_IMETHODIMP |
|
186 ChildDNSService::GetPrefetchEnabled(bool *outVal) |
|
187 { |
|
188 *outVal = !mDisablePrefetch; |
|
189 return NS_OK; |
|
190 } |
|
191 |
|
192 NS_IMETHODIMP |
|
193 ChildDNSService::SetPrefetchEnabled(bool inVal) |
|
194 { |
|
195 mDisablePrefetch = !inVal; |
|
196 return NS_OK; |
|
197 } |
|
198 |
|
199 NS_IMETHODIMP |
|
200 ChildDNSService::GetOffline(bool* aResult) |
|
201 { |
|
202 *aResult = mOffline; |
|
203 return NS_OK; |
|
204 } |
|
205 |
|
206 NS_IMETHODIMP |
|
207 ChildDNSService::SetOffline(bool value) |
|
208 { |
|
209 mOffline = value; |
|
210 return NS_OK; |
|
211 } |
|
212 |
|
213 //----------------------------------------------------------------------------- |
|
214 // ChildDNSService::nsIObserver |
|
215 //----------------------------------------------------------------------------- |
|
216 |
|
217 NS_IMETHODIMP |
|
218 ChildDNSService::Observe(nsISupports *subject, const char *topic, |
|
219 const char16_t *data) |
|
220 { |
|
221 // we are only getting called if a preference has changed. |
|
222 NS_ASSERTION(strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0, |
|
223 "unexpected observe call"); |
|
224 |
|
225 // Reread prefs |
|
226 Init(); |
|
227 return NS_OK; |
|
228 } |
|
229 |
|
230 } // namespace net |
|
231 } // namespace mozilla |