Chromium Code Reviews| 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/metrics/histogram_macros.h" | |
| 9 #include "base/timer/timer.h" | |
| 10 #include "base/values.h" | |
| 11 #include "net/base/net_errors.h" | |
| 12 #include "net/dns/dns_util.h" | |
| 13 #include "net/dns/host_resolver_impl.h" | |
| 14 | |
| 15 #define STALE_HISTOGRAM_ENUM(name, value, max) \ | |
|
xunjieli
2016/06/13 19:25:04
I am not sure if we want these defines. Can we inl
Julia Tuttle
2016/06/14 23:11:32
Done.
| |
| 16 UMA_HISTOGRAM_ENUMERATION("DNS.StaleHostResolver." name, value, max) | |
| 17 | |
| 18 #define STALE_HISTOGRAM_TIME(name, time) \ | |
| 19 UMA_HISTOGRAM_MEDIUM_TIMES("DNS.StaleHostResolver." name, time) | |
| 20 | |
| 21 namespace cronet { | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 // Used in histograms; do not modify existing values. | |
| 26 enum RequestOutcome { | |
| 27 // Served from (valid) cache, hosts file, IP literal, etc. | |
| 28 SYNCHRONOUS = 0, | |
| 29 | |
| 30 // Network responded; there was no usable stale data. | |
| 31 NETWORK_WITHOUT_STALE = 1, | |
| 32 | |
| 33 // Network responded before stale delay; there was usable stale data. | |
| 34 NETWORK_WITH_STALE = 2, | |
| 35 | |
| 36 // Stale data returned; network didn't respond before the stale delay. | |
| 37 STALE_BEFORE_NETWORK = 3, | |
| 38 | |
| 39 // Request canceled; there was no usable stale data. | |
| 40 CANCELED_WITHOUT_STALE = 4, | |
| 41 | |
| 42 // Request canceled; there was usable stale data. | |
| 43 CANCELED_WITH_STALE = 5, | |
| 44 | |
| 45 MAX_REQUEST_OUTCOME | |
| 46 }; | |
| 47 | |
| 48 void RecordRequestOutcome(RequestOutcome outcome) { | |
| 49 STALE_HISTOGRAM_ENUM("RequestOutcome", outcome, MAX_REQUEST_OUTCOME); | |
| 50 } | |
| 51 | |
| 52 void RecordAddressListDelta(net::AddressListDeltaType delta) { | |
| 53 STALE_HISTOGRAM_ENUM("StaleAddressListDelta", delta, net::MAX_DELTA_TYPE); | |
| 54 } | |
| 55 | |
| 56 void RecordTimeDelta(base::TimeTicks network_time, base::TimeTicks stale_time) { | |
| 57 if (network_time < stale_time) | |
| 58 STALE_HISTOGRAM_TIME("NetworkEarly", stale_time - network_time); | |
| 59 else | |
| 60 STALE_HISTOGRAM_TIME("NetworkLate", network_time - stale_time); | |
| 61 } | |
| 62 | |
| 63 } // namespace | |
| 64 | |
| 65 // A request made by the StaleHostResolver. May return fresh cached data, | |
| 66 // network data, or stale cached data. | |
| 67 class StaleHostResolver::Request { | |
| 68 public: | |
| 69 Request(); | |
| 70 | |
| 71 // A callback for the caller to decide whether a stale entry is usable or not. | |
| 72 typedef base::Callback<bool(const net::HostCache::EntryStaleness&)> | |
| 73 StaleEntryUsableCallback; | |
| 74 | |
| 75 // Starts the request. May call |usable_callback| inline if |resolver| returns | |
| 76 // stale data to let the caller decide whether the data is usable. | |
| 77 // | |
| 78 // Returns the result if the request finishes synchronously. Returns | |
| 79 // ERR_IO_PENDING and calls |callback| with the result if it finishes | |
| 80 // asynchronously, unless the requets is canceled (via |Cancel()|). | |
|
xunjieli
2016/06/13 19:25:04
typo in "request"
Julia Tuttle
2016/06/14 23:11:32
Done.
| |
| 81 // | |
| 82 // |addresses| must remain valid until the Request completes (synchronously or | |
| 83 // via |callback|) or is canceled (via |Cancel()|). | |
| 84 int Start(net::HostResolverImpl* resolver, | |
| 85 const RequestInfo& info, | |
| 86 net::RequestPriority priority, | |
| 87 net::AddressList* addresses, | |
| 88 const net::CompletionCallback& callback, | |
| 89 const net::BoundNetLog& net_log, | |
| 90 const StaleEntryUsableCallback& usable_callback, | |
| 91 base::TimeDelta stale_delay); | |
| 92 | |
| 93 // Cancels the request. |resolver| must be the same resolver passed to | |
| 94 // |Start()|. Does not call the callback passed to |Start()|. | |
| 95 // | |
| 96 // |Start()| must have been called and returned ERR_IO_PENDING; the request | |
| 97 // must not have been canceled already. | |
| 98 void Cancel(net::HostResolverImpl* resolver); | |
| 99 | |
| 100 bool has_network_request() const { return network_handle_ != nullptr; } | |
| 101 bool returned_stale_result() const { return callback_.is_null(); } | |
| 102 | |
| 103 private: | |
| 104 ~Request(); | |
| 105 | |
| 106 static int ResolveStale(net::HostResolverImpl* resolver, | |
|
xunjieli
2016/06/13 19:25:04
Need documentation, specifically, what the return
Julia Tuttle
2016/06/14 23:11:32
Done.
| |
| 107 const net::HostResolver::RequestInfo& info, | |
| 108 net::RequestPriority priority, | |
| 109 net::AddressList* addresses, | |
| 110 const net::CompletionCallback& callback, | |
| 111 net::HostResolver::RequestHandle* out_req, | |
| 112 int* stale_error, | |
| 113 net::AddressList* stale_addresses, | |
| 114 net::HostCache::EntryStaleness* stale_info, | |
| 115 const net::BoundNetLog& net_log); | |
| 116 | |
| 117 // Callback for the timer to return stale data. | |
| 118 void OnStaleDelayElapsed(); | |
| 119 | |
| 120 // Callback for the underlying network request. | |
| 121 void OnNetworkRequestComplete(int error); | |
| 122 | |
| 123 // Populates |*addresses_| from |addresses| if and only if rv is OK, clears | |
| 124 // |addresses_| to make sure the request doesn't return twice, and then | |
| 125 // returns |rv|. | |
| 126 int HandleResult(int rv, const net::AddressList& addresses); | |
| 127 | |
| 128 void RecordSynchronousRequest(); | |
| 129 void RecordNetworkRequest(int error); | |
| 130 void RecordCanceledRequest(); | |
| 131 | |
| 132 net::AddressList* addresses_; | |
| 133 net::CompletionCallback callback_; | |
| 134 | |
| 135 int stale_error_; | |
| 136 net::AddressList stale_addresses_; | |
| 137 base::OneShotTimer stale_timer_; | |
| 138 | |
| 139 net::AddressList network_addresses_; | |
| 140 net::HostResolver::RequestHandle network_handle_; | |
|
xunjieli
2016/06/13 19:25:03
need documentation on these member variables.
Julia Tuttle
2016/06/14 23:11:32
Done.
| |
| 141 }; | |
| 142 | |
| 143 StaleHostResolver::Request::Request() | |
| 144 : addresses_(nullptr), network_handle_(nullptr) {} | |
| 145 | |
| 146 int StaleHostResolver::Request::Start( | |
| 147 net::HostResolverImpl* resolver, | |
| 148 const RequestInfo& info, | |
| 149 net::RequestPriority priority, | |
| 150 net::AddressList* addresses, | |
| 151 const net::CompletionCallback& callback, | |
| 152 const net::BoundNetLog& net_log, | |
| 153 const StaleEntryUsableCallback& usable_callback, | |
| 154 base::TimeDelta stale_delay) { | |
| 155 DCHECK(!callback.is_null()); | |
| 156 DCHECK(!usable_callback.is_null()); | |
| 157 | |
| 158 callback_ = callback; | |
| 159 addresses_ = addresses; | |
| 160 | |
| 161 // Request never deletes itself until the network request returns (if one is | |
| 162 // started), so it's safe to use Unretained here. | |
| 163 net::CompletionCallback network_callback = | |
| 164 base::Bind(&StaleHostResolver::Request::OnNetworkRequestComplete, | |
| 165 base::Unretained(this)); | |
| 166 net::HostCache::EntryStaleness stale_info; | |
| 167 int rv = ResolveStale(resolver, info, priority, &network_addresses_, | |
| 168 network_callback, &network_handle_, &stale_error_, | |
| 169 &stale_addresses_, &stale_info, net_log); | |
| 170 if (rv != net::ERR_IO_PENDING) { | |
| 171 DCHECK(!network_handle_); | |
| 172 rv = HandleResult(rv, network_addresses_); | |
| 173 RecordSynchronousRequest(); | |
| 174 delete this; | |
| 175 return rv; | |
| 176 } | |
| 177 | |
| 178 if (stale_error_ != net::ERR_DNS_CACHE_MISS && | |
| 179 usable_callback.Run(stale_info)) { | |
| 180 // |stale_timer_| is deleted when the Request is deleted, so it's safe to | |
| 181 // use Unretained here. | |
| 182 base::Callback<void()> stale_callback = | |
| 183 base::Bind(&StaleHostResolver::Request::OnStaleDelayElapsed, | |
| 184 base::Unretained(this)); | |
| 185 stale_timer_.Start(FROM_HERE, stale_delay, stale_callback); | |
| 186 } else { | |
| 187 stale_addresses_.clear(); | |
| 188 } | |
| 189 | |
| 190 return net::ERR_IO_PENDING; | |
| 191 } | |
| 192 | |
| 193 void StaleHostResolver::Request::Cancel(net::HostResolverImpl* resolver) { | |
| 194 DCHECK(has_network_request()); | |
| 195 DCHECK(!returned_stale_result()); | |
| 196 | |
| 197 resolver->CancelRequest(network_handle_); | |
| 198 network_handle_ = nullptr; | |
| 199 | |
| 200 RecordCanceledRequest(); | |
| 201 delete this; | |
| 202 } | |
| 203 | |
| 204 StaleHostResolver::Request::~Request() { | |
| 205 DCHECK(!has_network_request()); | |
| 206 } | |
| 207 | |
| 208 // static | |
| 209 int StaleHostResolver::Request::ResolveStale( | |
| 210 net::HostResolverImpl* resolver, | |
| 211 const net::HostResolver::RequestInfo& info, | |
| 212 net::RequestPriority priority, | |
| 213 net::AddressList* addresses, | |
| 214 const net::CompletionCallback& callback, | |
| 215 net::HostResolver::RequestHandle* out_req, | |
| 216 int* stale_error, | |
| 217 net::AddressList* stale_addresses, | |
| 218 net::HostCache::EntryStaleness* stale_info, | |
| 219 const net::BoundNetLog& net_log) { | |
| 220 net::AddressList cache_addresses; | |
| 221 int cache_rv = resolver->ResolveStaleFromCache(info, &cache_addresses, | |
| 222 stale_info, net_log); | |
| 223 // If it's a fresh cache hit (or literal), return it synchronously. | |
| 224 if (cache_rv != net::ERR_DNS_CACHE_MISS && !stale_info->is_stale()) { | |
| 225 *stale_error = net::ERR_UNEXPECTED; | |
| 226 *addresses = cache_addresses; | |
| 227 return cache_rv; | |
| 228 } | |
| 229 | |
| 230 // If it's a stale cache hit, fill in |*stale_addresses| but run the network | |
| 231 // request anyway. | |
| 232 if (cache_rv != net::ERR_DNS_CACHE_MISS) | |
| 233 *stale_addresses = cache_addresses; | |
| 234 | |
| 235 *stale_error = cache_rv; | |
| 236 | |
| 237 // Don't check the cache again. | |
| 238 net::HostResolver::RequestInfo no_cache_info(info); | |
| 239 no_cache_info.set_allow_cached_response(false); | |
| 240 return resolver->Resolve(no_cache_info, priority, addresses, callback, | |
| 241 out_req, net_log); | |
| 242 } | |
| 243 | |
| 244 void StaleHostResolver::Request::OnStaleDelayElapsed() { | |
| 245 DCHECK(has_network_request()); | |
| 246 DCHECK(!returned_stale_result()); | |
| 247 | |
| 248 base::ResetAndReturn(&callback_) | |
| 249 .Run(HandleResult(stale_error_, stale_addresses_)); | |
| 250 | |
| 251 // Don't delete |this|; let the underlying request continue to backfill the | |
| 252 // host cache. | |
| 253 } | |
| 254 | |
| 255 void StaleHostResolver::Request::OnNetworkRequestComplete(int error) { | |
| 256 DCHECK(has_network_request()); | |
| 257 | |
| 258 network_handle_ = nullptr; | |
| 259 | |
| 260 if (!returned_stale_result()) | |
| 261 callback_.Run(HandleResult(error, network_addresses_)); | |
| 262 | |
| 263 RecordNetworkRequest(error); | |
| 264 delete this; | |
| 265 } | |
| 266 | |
| 267 int StaleHostResolver::Request::HandleResult( | |
| 268 int rv, | |
| 269 const net::AddressList& addresses) { | |
| 270 DCHECK(addresses_); | |
| 271 | |
| 272 if (rv == net::OK) | |
| 273 *addresses_ = addresses; | |
| 274 addresses_ = nullptr; | |
| 275 return rv; | |
| 276 } | |
| 277 | |
| 278 void StaleHostResolver::Request::RecordSynchronousRequest() { | |
| 279 RecordRequestOutcome(SYNCHRONOUS); | |
| 280 } | |
| 281 | |
| 282 void StaleHostResolver::Request::RecordNetworkRequest(int error) { | |
| 283 if (stale_timer_.IsRunning() || returned_stale_result()) | |
| 284 RecordTimeDelta(base::TimeTicks::Now(), stale_timer_.desired_run_time()); | |
| 285 | |
| 286 if (returned_stale_result() && stale_error_ == net::OK && error == net::OK) { | |
| 287 RecordAddressListDelta( | |
| 288 FindAddressListDeltaType(stale_addresses_, network_addresses_)); | |
| 289 } | |
| 290 | |
| 291 if (returned_stale_result()) | |
| 292 RecordRequestOutcome(STALE_BEFORE_NETWORK); | |
| 293 else if (stale_timer_.IsRunning()) | |
| 294 RecordRequestOutcome(NETWORK_WITH_STALE); | |
| 295 else | |
| 296 RecordRequestOutcome(NETWORK_WITHOUT_STALE); | |
| 297 } | |
| 298 | |
| 299 void StaleHostResolver::Request::RecordCanceledRequest() { | |
| 300 if (stale_timer_.IsRunning()) | |
| 301 RecordRequestOutcome(CANCELED_WITH_STALE); | |
| 302 else | |
| 303 RecordRequestOutcome(CANCELED_WITHOUT_STALE); | |
| 304 } | |
| 305 | |
| 306 namespace { | |
| 307 | |
| 308 bool StaleEntryIsUsable(const StaleHostResolver::StaleOptions& options, | |
| 309 const net::HostCache::EntryStaleness& entry) { | |
| 310 if (options.max_expired_time != base::TimeDelta() && | |
| 311 entry.expired_by > options.max_expired_time) { | |
| 312 return false; | |
| 313 } | |
| 314 if (options.max_stale_uses > 0 && entry.stale_hits > options.max_stale_uses) | |
| 315 return false; | |
| 316 if (!options.allow_other_network && entry.network_changes > 0) | |
| 317 return false; | |
| 318 return true; | |
| 319 } | |
| 320 | |
| 321 } // namespace | |
|
xunjieli
2016/06/13 19:25:03
Can we have the anonymous namespaces at the top of
Julia Tuttle
2016/06/14 23:11:32
Done.
| |
| 322 | |
| 323 StaleHostResolver::StaleHostResolver( | |
| 324 std::unique_ptr<net::HostResolverImpl> inner_resolver, | |
| 325 const StaleOptions& stale_options) | |
| 326 : resolver_(std::move(inner_resolver)), options_(stale_options) { | |
|
xunjieli
2016/06/13 19:25:04
nit: Can we rename |resolver_| to |inner_resolver_
Julia Tuttle
2016/06/14 23:11:32
Done.
| |
| 327 DCHECK_GE(0, stale_options.max_expired_time.InMicroseconds()); | |
| 328 DCHECK_GE(0, stale_options.max_stale_uses); | |
| 329 } | |
| 330 | |
| 331 StaleHostResolver::~StaleHostResolver() { | |
| 332 for (auto* request : pending_requests_) | |
| 333 request->Cancel(resolver_.get()); | |
| 334 pending_requests_.clear(); | |
| 335 } | |
| 336 | |
| 337 int StaleHostResolver::Resolve(const RequestInfo& info, | |
| 338 net::RequestPriority priority, | |
| 339 net::AddressList* addresses, | |
| 340 const net::CompletionCallback& callback, | |
| 341 RequestHandle* out_req, | |
| 342 const net::BoundNetLog& net_log) { | |
| 343 StaleHostResolver::Request::StaleEntryUsableCallback usable_callback = | |
| 344 base::Bind(&StaleEntryIsUsable, options_); | |
| 345 | |
| 346 Request* request = new Request(); | |
| 347 pending_requests_.insert(request); | |
|
xunjieli
2016/06/13 19:25:04
If request->Start() finishes synchronously, can we
Julia Tuttle
2016/06/14 23:11:32
Done.
| |
| 348 // If Request is not complete when the StaleHostResolver is being destroyed, | |
| 349 // the destructor will Cancel it, preventing this callback from being called, | |
| 350 // so it's safe to use Unretained here. | |
| 351 net::CompletionCallback wrapped_callback = | |
| 352 base::Bind(&StaleHostResolver::OnRequestComplete, base::Unretained(this), | |
| 353 request, callback); | |
| 354 | |
| 355 int rv = request->Start(resolver_.get(), info, priority, addresses, | |
| 356 wrapped_callback, net_log, usable_callback, | |
| 357 options_.delay); | |
| 358 if (rv == net::ERR_IO_PENDING && out_req) | |
| 359 *out_req = reinterpret_cast<RequestHandle>(request); | |
| 360 return rv; | |
| 361 } | |
| 362 | |
| 363 void StaleHostResolver::CancelRequest(RequestHandle req_handle) { | |
| 364 Request* request = reinterpret_cast<Request*>(req_handle); | |
| 365 DCHECK(request); | |
| 366 DCHECK_EQ(1u, pending_requests_.count(request)); | |
| 367 | |
| 368 request->Cancel(resolver_.get()); | |
| 369 pending_requests_.erase(request); | |
| 370 } | |
| 371 | |
| 372 int StaleHostResolver::ResolveFromCache(const RequestInfo& info, | |
| 373 net::AddressList* addresses, | |
| 374 const net::BoundNetLog& net_log) { | |
| 375 return resolver_->ResolveFromCache(info, addresses, net_log); | |
| 376 } | |
| 377 | |
| 378 void StaleHostResolver::SetDnsClientEnabled(bool enabled) { | |
| 379 resolver_->SetDnsClientEnabled(enabled); | |
| 380 } | |
| 381 | |
| 382 net::HostCache* StaleHostResolver::GetHostCache() { | |
| 383 return resolver_->GetHostCache(); | |
| 384 } | |
| 385 | |
| 386 std::unique_ptr<base::Value> StaleHostResolver::GetDnsConfigAsValue() const { | |
| 387 return resolver_->GetDnsConfigAsValue(); | |
| 388 } | |
| 389 | |
| 390 void StaleHostResolver::OnRequestComplete( | |
| 391 StaleHostResolver::Request* request, | |
| 392 const net::CompletionCallback& outer_callback, | |
| 393 int error) { | |
| 394 DCHECK(request); | |
| 395 DCHECK_NE(net::ERR_IO_PENDING, error); | |
| 396 | |
| 397 DCHECK_EQ(1u, pending_requests_.count(request)); | |
| 398 pending_requests_.erase(request); | |
|
xunjieli
2016/06/13 19:25:04
Instead of deleting |request| in OnNetworkRequestC
Julia Tuttle
2016/06/14 23:11:32
Done.
| |
| 399 | |
| 400 outer_callback.Run(error); | |
| 401 } | |
| 402 | |
| 403 } // namespace net | |
| OLD | NEW |