OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/cronet/stale_host_resolver.h" | |
6 | |
7 #include "base/callback_helpers.h" | |
8 #include "base/memory/ptr_util.h" | |
9 #include "base/metrics/histogram_macros.h" | |
10 #include "base/stl_util.h" | |
11 #include "base/timer/timer.h" | |
12 #include "base/values.h" | |
13 #include "net/base/net_errors.h" | |
14 #include "net/dns/dns_util.h" | |
15 #include "net/dns/host_resolver_impl.h" | |
16 | |
17 namespace cronet { | |
18 | |
19 namespace { | |
20 | |
21 // Used in histograms; do not modify existing values. | |
22 enum RequestOutcome { | |
23 // Served from (valid) cache, hosts file, IP literal, etc. | |
24 SYNCHRONOUS = 0, | |
25 | |
26 // Network responded; there was no usable stale data. | |
27 NETWORK_WITHOUT_STALE = 1, | |
28 | |
29 // Network responded before stale delay; there was usable stale data. | |
30 NETWORK_WITH_STALE = 2, | |
31 | |
32 // Stale data returned; network didn't respond before the stale delay. | |
33 STALE_BEFORE_NETWORK = 3, | |
34 | |
35 // Request canceled; there was no usable stale data. | |
36 CANCELED_WITHOUT_STALE = 4, | |
37 | |
38 // Request canceled; there was usable stale data. | |
39 CANCELED_WITH_STALE = 5, | |
40 | |
41 MAX_REQUEST_OUTCOME | |
42 }; | |
43 | |
44 void RecordRequestOutcome(RequestOutcome outcome) { | |
45 UMA_HISTOGRAM_ENUMERATION("DNS.StaleHostResolver.RequestOutcome", outcome, | |
46 MAX_REQUEST_OUTCOME); | |
47 } | |
48 | |
49 void RecordAddressListDelta(net::AddressListDeltaType delta) { | |
50 UMA_HISTOGRAM_ENUMERATION("DNS.StaleHostResolver.StaleAddressListDelta", | |
51 delta, net::MAX_DELTA_TYPE); | |
52 } | |
53 | |
54 void RecordTimeDelta(base::TimeTicks network_time, base::TimeTicks stale_time) { | |
55 if (network_time < stale_time) { | |
56 UMA_HISTOGRAM_MEDIUM_TIMES("DNS.StaleHostResolver.NetworkEarly", | |
57 stale_time - network_time); | |
58 } else { | |
59 UMA_HISTOGRAM_MEDIUM_TIMES("DNS.StaleHostResolver.NetworkLate", | |
Mark P
2016/08/08 19:16:21
Is medium times the right macro here? Typical ran
Julia Tuttle
2016/08/09 12:50:32
Good call. I'll use UMA_HISTOGRAM_LONG_TIMES_100 i
| |
60 network_time - stale_time); | |
61 } | |
62 } | |
63 | |
64 bool StaleEntryIsUsable(const StaleHostResolver::StaleOptions& options, | |
65 const net::HostCache::EntryStaleness& entry) { | |
66 if (options.max_expired_time != base::TimeDelta() && | |
67 entry.expired_by > options.max_expired_time) { | |
68 return false; | |
69 } | |
70 if (options.max_stale_uses > 0 && entry.stale_hits > options.max_stale_uses) | |
71 return false; | |
72 if (!options.allow_other_network && entry.network_changes > 0) | |
73 return false; | |
74 return true; | |
75 } | |
76 | |
77 } // namespace | |
78 | |
79 // A request made by the StaleHostResolver. May return fresh cached data, | |
80 // network data, or stale cached data. | |
81 class StaleHostResolver::RequestImpl { | |
82 public: | |
83 RequestImpl(); | |
84 ~RequestImpl(); | |
85 | |
86 // A callback for the caller to decide whether a stale entry is usable or not. | |
87 typedef base::Callback<bool(const net::HostCache::EntryStaleness&)> | |
88 StaleEntryUsableCallback; | |
89 | |
90 // Starts the request. May call |usable_callback| inline if |resolver| returns | |
91 // stale data to let the caller decide whether the data is usable. | |
92 // | |
93 // Returns the result if the request finishes synchronously. Returns | |
94 // ERR_IO_PENDING and calls |result_callback| with the result if it finishes | |
95 // asynchronously (unless destroyed first). | |
96 // | |
97 // |addresses| must remain valid until the Request completes (synchronously or | |
98 // via |result_callback|) or is canceled by destroying the Request. | |
99 int Start(net::HostResolverImpl* resolver, | |
100 const RequestInfo& info, | |
101 net::RequestPriority priority, | |
102 net::AddressList* addresses, | |
103 const net::CompletionCallback& result_callback, | |
104 std::unique_ptr<net::HostResolver::Request>* out_req, | |
105 const net::BoundNetLog& net_log, | |
106 const StaleEntryUsableCallback& usable_callback, | |
107 base::TimeDelta stale_delay); | |
108 | |
109 void ChangeRequestPriority(net::RequestPriority priority); | |
110 | |
111 private: | |
112 class Handle : public net::HostResolver::Request { | |
113 public: | |
114 Handle(RequestImpl* request) : request_(request) {} | |
115 ~Handle() override { request_->OnHandleDestroyed(); } | |
116 | |
117 void ChangeRequestPriority(net::RequestPriority priority) override { | |
118 request_->ChangeRequestPriority(priority); | |
119 } | |
120 | |
121 private: | |
122 RequestImpl* request_; | |
123 }; | |
124 | |
125 bool have_network_request() const { | |
126 return network_request_.get() != nullptr; | |
127 } | |
128 bool have_stale_data() const { | |
129 return stale_error_ != net::ERR_DNS_CACHE_MISS; | |
130 } | |
131 bool have_returned() const { return result_callback_.is_null(); } | |
132 bool have_handle() const { return handle_ != nullptr; } | |
133 | |
134 // Callback for |stale_timer_| that returns stale results. | |
135 void OnStaleDelayElapsed(); | |
136 // Callback for network request that returns fresh results if the request | |
137 // hasn't already returned stale results, and completes the request. | |
138 void OnNetworkRequestComplete(int error); | |
139 void OnHandleDestroyed(); | |
140 | |
141 // Fills |*result_addresses_| if rv is OK and returns rv. | |
142 int HandleResult(int rv, net::AddressList* addresses); | |
143 // Fills |*result_addresses_| if rv is OK and calls |result_callback_| with | |
144 // rv. | |
145 void ReturnResult(int rv, net::AddressList* addresses); | |
146 | |
147 void MaybeDeleteThis(); | |
148 | |
149 void RecordSynchronousRequest(); | |
150 void RecordNetworkRequest(int error, bool returned_stale_data); | |
151 void RecordCanceledRequest(); | |
152 | |
153 // The address list passed into |Start()| to be filled in when the request | |
154 // returns. | |
155 net::AddressList* result_addresses_; | |
156 // The callback passed into |Start()| to be called when the request returns. | |
157 net::CompletionCallback result_callback_; | |
158 // Set when |result_callback_| is being called so |OnHandleDestroyed()| | |
159 // doesn't delete the request. | |
160 bool returning_result_; | |
161 | |
162 // The error from the stale cache entry, if there was one. | |
163 // If not, net::ERR_DNS_CACHE_MISS. | |
164 int stale_error_; | |
165 // The address list from the stale cache entry, if there was one. | |
166 net::AddressList stale_addresses_; | |
167 // A timer that fires when the |Request| should return stale results, if the | |
168 // underlying network request has not finished yet. | |
169 base::OneShotTimer stale_timer_; | |
170 | |
171 // The address list the underlying network request will fill in. (Can't be the | |
172 // one passed to |Start()|, or else the network request would overwrite stale | |
173 // results after they are returned.) | |
174 net::AddressList network_addresses_; | |
175 // The underlying network request, so the priority can be changed. | |
176 std::unique_ptr<net::HostResolver::Request> network_request_; | |
177 | |
178 // Handle that caller can use to cancel the request before it returns. | |
179 // Owned by the caller; cleared via |OnHandleDestroyed()| when destroyed. | |
180 Handle* handle_; | |
181 }; | |
182 | |
183 StaleHostResolver::RequestImpl::RequestImpl() | |
184 : result_addresses_(nullptr), | |
185 returning_result_(false), | |
186 stale_error_(net::ERR_DNS_CACHE_MISS), | |
187 handle_(nullptr) {} | |
188 | |
189 StaleHostResolver::RequestImpl::~RequestImpl() {} | |
190 | |
191 int StaleHostResolver::RequestImpl::Start( | |
192 net::HostResolverImpl* resolver, | |
193 const RequestInfo& info, | |
194 net::RequestPriority priority, | |
195 net::AddressList* addresses, | |
196 const net::CompletionCallback& result_callback, | |
197 std::unique_ptr<net::HostResolver::Request>* out_req, | |
198 const net::BoundNetLog& net_log, | |
199 const StaleEntryUsableCallback& usable_callback, | |
200 base::TimeDelta stale_delay) { | |
201 DCHECK(resolver); | |
202 DCHECK(addresses); | |
203 DCHECK(!result_callback.is_null()); | |
204 DCHECK(out_req); | |
205 DCHECK(!usable_callback.is_null()); | |
206 | |
207 result_addresses_ = addresses; | |
208 | |
209 net::AddressList cache_addresses; | |
210 net::HostCache::EntryStaleness stale_info; | |
211 int cache_rv = resolver->ResolveStaleFromCache(info, &cache_addresses, | |
212 &stale_info, net_log); | |
213 // If it's a fresh cache hit (or literal), return it synchronously. | |
214 if (cache_rv != net::ERR_DNS_CACHE_MISS && !stale_info.is_stale()) { | |
215 RecordSynchronousRequest(); | |
216 return HandleResult(cache_rv, &cache_addresses); | |
217 } | |
218 | |
219 result_callback_ = result_callback; | |
220 handle_ = new Handle(this); | |
221 *out_req = std::unique_ptr<net::HostResolver::Request>(handle_); | |
222 | |
223 if (cache_rv != net::ERR_DNS_CACHE_MISS && usable_callback.Run(stale_info)) { | |
224 stale_error_ = cache_rv; | |
225 stale_addresses_ = cache_addresses; | |
226 // |stale_timer_| is deleted when the Request is deleted, so it's safe to | |
227 // use Unretained here. | |
228 base::Callback<void()> stale_callback = | |
229 base::Bind(&StaleHostResolver::RequestImpl::OnStaleDelayElapsed, | |
230 base::Unretained(this)); | |
231 stale_timer_.Start(FROM_HERE, stale_delay, stale_callback); | |
232 } | |
233 | |
234 // Don't check the cache again. | |
235 net::HostResolver::RequestInfo no_cache_info(info); | |
236 no_cache_info.set_allow_cached_response(false); | |
237 int network_rv = resolver->Resolve( | |
238 no_cache_info, priority, &network_addresses_, | |
239 base::Bind(&StaleHostResolver::RequestImpl::OnNetworkRequestComplete, | |
240 base::Unretained(this)), | |
241 &network_request_, net_log); | |
242 DCHECK_EQ(net::ERR_IO_PENDING, network_rv); | |
243 return net::ERR_IO_PENDING; | |
244 } | |
245 | |
246 void StaleHostResolver::RequestImpl::ChangeRequestPriority( | |
247 net::RequestPriority priority) { | |
248 DCHECK(have_network_request()); | |
249 | |
250 network_request_->ChangeRequestPriority(priority); | |
251 } | |
252 | |
253 void StaleHostResolver::RequestImpl::OnStaleDelayElapsed() { | |
254 DCHECK(!have_returned()); | |
255 DCHECK(have_stale_data()); | |
256 | |
257 ReturnResult(stale_error_, &stale_addresses_); | |
258 | |
259 // The request needs to wait for both the network request to complete (to | |
260 // backfill the cache) and the caller to delete the handle before deleting | |
261 // itself. | |
262 DCHECK(have_network_request()); | |
263 } | |
264 | |
265 void StaleHostResolver::RequestImpl::OnNetworkRequestComplete(int error) { | |
266 DCHECK(have_network_request()); | |
267 network_request_.reset(); | |
268 | |
269 RecordNetworkRequest(error, /* returned_stale_data = */ have_returned()); | |
270 | |
271 if (!have_returned()) { | |
272 if (have_stale_data()) | |
273 stale_timer_.Stop(); | |
274 ReturnResult(error, &network_addresses_); | |
275 } | |
276 | |
277 if (!have_handle()) | |
278 delete this; | |
279 } | |
280 | |
281 void StaleHostResolver::RequestImpl::OnHandleDestroyed() { | |
282 DCHECK(have_handle()); | |
283 handle_ = nullptr; | |
284 | |
285 // If the caller deletes the handle *before* the request has returned, treat | |
286 // it as a cancel. | |
287 if (!have_returned()) { | |
288 network_request_.reset(); | |
289 result_callback_ = net::CompletionCallback(); | |
290 RecordCanceledRequest(); | |
291 } | |
292 | |
293 if (!returning_result_ && !have_handle() && !have_network_request()) | |
294 delete this; | |
295 } | |
296 | |
297 int StaleHostResolver::RequestImpl::HandleResult(int rv, | |
298 net::AddressList* addresses) { | |
299 DCHECK(result_addresses_); | |
300 | |
301 if (rv == net::OK) { | |
302 *result_addresses_ = *addresses; | |
303 addresses->clear(); | |
304 } | |
305 result_addresses_ = nullptr; | |
306 return rv; | |
307 } | |
308 | |
309 void StaleHostResolver::RequestImpl::ReturnResult(int rv, | |
310 net::AddressList* addresses) { | |
311 DCHECK(result_callback_); | |
312 returning_result_ = true; | |
313 base::ResetAndReturn(&result_callback_).Run(HandleResult(rv, addresses)); | |
314 returning_result_ = false; | |
315 } | |
316 | |
317 void StaleHostResolver::RequestImpl::RecordSynchronousRequest() { | |
318 RecordRequestOutcome(SYNCHRONOUS); | |
319 } | |
320 | |
321 void StaleHostResolver::RequestImpl::RecordNetworkRequest( | |
322 int error, | |
323 bool returned_stale_data) { | |
324 if (have_stale_data()) | |
325 RecordTimeDelta(base::TimeTicks::Now(), stale_timer_.desired_run_time()); | |
326 | |
327 if (returned_stale_data && stale_error_ == net::OK && error == net::OK) { | |
328 RecordAddressListDelta( | |
329 FindAddressListDeltaType(stale_addresses_, network_addresses_)); | |
330 } | |
331 | |
332 if (returned_stale_data) | |
333 RecordRequestOutcome(STALE_BEFORE_NETWORK); | |
334 else if (have_stale_data()) | |
335 RecordRequestOutcome(NETWORK_WITH_STALE); | |
336 else | |
337 RecordRequestOutcome(NETWORK_WITHOUT_STALE); | |
338 } | |
339 | |
340 void StaleHostResolver::RequestImpl::RecordCanceledRequest() { | |
341 if (have_stale_data()) | |
342 RecordRequestOutcome(CANCELED_WITH_STALE); | |
343 else | |
344 RecordRequestOutcome(CANCELED_WITHOUT_STALE); | |
345 } | |
346 | |
347 StaleHostResolver::StaleOptions::StaleOptions() | |
348 : delay(), | |
349 max_expired_time(), | |
350 allow_other_network(false), | |
351 max_stale_uses(0) {} | |
352 | |
353 StaleHostResolver::StaleHostResolver( | |
354 std::unique_ptr<net::HostResolverImpl> inner_resolver, | |
355 const StaleOptions& stale_options) | |
356 : inner_resolver_(std::move(inner_resolver)), options_(stale_options) { | |
357 DCHECK_LE(0, stale_options.max_expired_time.InMicroseconds()); | |
358 DCHECK_LE(0, stale_options.max_stale_uses); | |
359 } | |
360 | |
361 StaleHostResolver::~StaleHostResolver() {} | |
362 | |
363 int StaleHostResolver::Resolve(const RequestInfo& info, | |
364 net::RequestPriority priority, | |
365 net::AddressList* addresses, | |
366 const net::CompletionCallback& callback, | |
367 std::unique_ptr<Request>* out_req, | |
368 const net::BoundNetLog& net_log) { | |
369 StaleHostResolver::RequestImpl::StaleEntryUsableCallback usable_callback = | |
370 base::Bind(&StaleEntryIsUsable, options_); | |
371 | |
372 RequestImpl* request = new RequestImpl(); | |
373 int rv = | |
374 request->Start(inner_resolver_.get(), info, priority, addresses, callback, | |
375 out_req, net_log, usable_callback, options_.delay); | |
376 if (rv != net::ERR_IO_PENDING) | |
377 delete request; | |
378 | |
379 return rv; | |
380 } | |
381 | |
382 int StaleHostResolver::ResolveFromCache(const RequestInfo& info, | |
383 net::AddressList* addresses, | |
384 const net::BoundNetLog& net_log) { | |
385 return inner_resolver_->ResolveFromCache(info, addresses, net_log); | |
386 } | |
387 | |
388 void StaleHostResolver::SetDnsClientEnabled(bool enabled) { | |
389 inner_resolver_->SetDnsClientEnabled(enabled); | |
390 } | |
391 | |
392 net::HostCache* StaleHostResolver::GetHostCache() { | |
393 return inner_resolver_->GetHostCache(); | |
394 } | |
395 | |
396 std::unique_ptr<base::Value> StaleHostResolver::GetDnsConfigAsValue() const { | |
397 return inner_resolver_->GetDnsConfigAsValue(); | |
398 } | |
399 | |
400 } // namespace net | |
OLD | NEW |