OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/domain_reliability/monitor.h" | 5 #include "components/domain_reliability/monitor.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/profiler/scoped_tracker.h" | 9 #include "base/profiler/scoped_tracker.h" |
10 #include "base/single_thread_task_runner.h" | 10 #include "base/single_thread_task_runner.h" |
11 #include "base/task_runner.h" | 11 #include "base/task_runner.h" |
12 #include "base/time/time.h" | 12 #include "base/time/time.h" |
13 #include "components/domain_reliability/baked_in_configs.h" | 13 #include "components/domain_reliability/baked_in_configs.h" |
| 14 #include "net/base/ip_endpoint.h" |
14 #include "net/base/load_flags.h" | 15 #include "net/base/load_flags.h" |
| 16 #include "net/base/net_errors.h" |
| 17 #include "net/base/net_util.h" |
15 #include "net/http/http_response_headers.h" | 18 #include "net/http/http_response_headers.h" |
16 #include "net/url_request/url_request.h" | 19 #include "net/url_request/url_request.h" |
17 #include "net/url_request/url_request_context.h" | 20 #include "net/url_request/url_request_context.h" |
18 #include "net/url_request/url_request_context_getter.h" | 21 #include "net/url_request/url_request_context_getter.h" |
19 | 22 |
20 namespace domain_reliability { | 23 namespace domain_reliability { |
21 | 24 |
| 25 namespace { |
| 26 |
| 27 int URLRequestStatusToNetError(const net::URLRequestStatus& status) { |
| 28 switch (status.status()) { |
| 29 case net::URLRequestStatus::SUCCESS: |
| 30 return net::OK; |
| 31 case net::URLRequestStatus::IO_PENDING: |
| 32 return net::ERR_IO_PENDING; |
| 33 case net::URLRequestStatus::CANCELED: |
| 34 return net::ERR_ABORTED; |
| 35 case net::URLRequestStatus::FAILED: |
| 36 return status.error(); |
| 37 default: |
| 38 NOTREACHED(); |
| 39 return net::ERR_UNEXPECTED; |
| 40 } |
| 41 } |
| 42 |
| 43 // Updates the status, chrome_error, and server_ip fields of |beacon| from |
| 44 // the endpoint and result of |attempt|. If there is no matching status for |
| 45 // the result, returns false (which means the attempt should not result in a |
| 46 // beacon being reported). |
| 47 bool UpdateBeaconFromAttempt(DomainReliabilityBeacon* beacon, |
| 48 const net::ConnectionAttempt& attempt) { |
| 49 if (!GetDomainReliabilityBeaconStatus( |
| 50 attempt.result, beacon->http_response_code, &beacon->status)) { |
| 51 return false; |
| 52 } |
| 53 beacon->chrome_error = attempt.result; |
| 54 if (!attempt.endpoint.address().empty()) |
| 55 beacon->server_ip = attempt.endpoint.ToString(); |
| 56 else |
| 57 beacon->server_ip = ""; |
| 58 return true; |
| 59 } |
| 60 |
| 61 // TODO(ttuttle): This function is absurd. See if |socket_address| in |
| 62 // HttpResponseInfo can become an IPEndPoint. |
| 63 bool ConvertHostPortPairToIPEndPoint(const net::HostPortPair& host_port_pair, |
| 64 net::IPEndPoint* ip_endpoint_out) { |
| 65 net::IPAddressNumber ip_address_number; |
| 66 if (!net::ParseIPLiteralToNumber(host_port_pair.host(), &ip_address_number)) |
| 67 return false; |
| 68 *ip_endpoint_out = net::IPEndPoint(ip_address_number, host_port_pair.port()); |
| 69 return true; |
| 70 } |
| 71 |
| 72 } // namespace |
| 73 |
22 DomainReliabilityMonitor::DomainReliabilityMonitor( | 74 DomainReliabilityMonitor::DomainReliabilityMonitor( |
23 const std::string& upload_reporter_string, | 75 const std::string& upload_reporter_string, |
24 const scoped_refptr<base::SingleThreadTaskRunner>& pref_thread, | 76 const scoped_refptr<base::SingleThreadTaskRunner>& pref_thread, |
25 const scoped_refptr<base::SingleThreadTaskRunner>& network_thread) | 77 const scoped_refptr<base::SingleThreadTaskRunner>& network_thread) |
26 : time_(new ActualTime()), | 78 : time_(new ActualTime()), |
27 upload_reporter_string_(upload_reporter_string), | 79 upload_reporter_string_(upload_reporter_string), |
28 scheduler_params_( | 80 scheduler_params_( |
29 DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()), | 81 DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()), |
30 dispatcher_(time_.get()), | 82 dispatcher_(time_.get()), |
31 context_manager_(this), | 83 context_manager_(this), |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 } | 195 } |
144 | 196 |
145 void DomainReliabilityMonitor::OnCompleted(net::URLRequest* request, | 197 void DomainReliabilityMonitor::OnCompleted(net::URLRequest* request, |
146 bool started) { | 198 bool started) { |
147 DCHECK(OnNetworkThread()); | 199 DCHECK(OnNetworkThread()); |
148 DCHECK(discard_uploads_set_); | 200 DCHECK(discard_uploads_set_); |
149 | 201 |
150 if (!started) | 202 if (!started) |
151 return; | 203 return; |
152 RequestInfo request_info(*request); | 204 RequestInfo request_info(*request); |
153 if (request_info.AccessedNetwork()) { | 205 OnRequestLegComplete(request_info); |
154 OnRequestLegComplete(request_info); | 206 |
| 207 if (request_info.response_info.network_accessed) { |
155 // A request was just using the network, so now is a good time to run any | 208 // A request was just using the network, so now is a good time to run any |
156 // pending and eligible uploads. | 209 // pending and eligible uploads. |
157 dispatcher_.RunEligibleTasks(); | 210 dispatcher_.RunEligibleTasks(); |
158 } | 211 } |
159 } | 212 } |
160 | 213 |
161 void DomainReliabilityMonitor::OnNetworkChanged( | 214 void DomainReliabilityMonitor::OnNetworkChanged( |
162 net::NetworkChangeNotifier::ConnectionType type) { | 215 net::NetworkChangeNotifier::ConnectionType type) { |
163 last_network_change_time_ = time_->NowTicks(); | 216 last_network_change_time_ = time_->NowTicks(); |
164 } | 217 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 DomainReliabilityMonitor::RequestInfo::RequestInfo() {} | 267 DomainReliabilityMonitor::RequestInfo::RequestInfo() {} |
215 | 268 |
216 DomainReliabilityMonitor::RequestInfo::RequestInfo( | 269 DomainReliabilityMonitor::RequestInfo::RequestInfo( |
217 const net::URLRequest& request) | 270 const net::URLRequest& request) |
218 : url(request.url()), | 271 : url(request.url()), |
219 status(request.status()), | 272 status(request.status()), |
220 response_info(request.response_info()), | 273 response_info(request.response_info()), |
221 load_flags(request.load_flags()), | 274 load_flags(request.load_flags()), |
222 is_upload(DomainReliabilityUploader::URLRequestIsUpload(request)) { | 275 is_upload(DomainReliabilityUploader::URLRequestIsUpload(request)) { |
223 request.GetLoadTimingInfo(&load_timing_info); | 276 request.GetLoadTimingInfo(&load_timing_info); |
| 277 request.GetConnectionAttempts(&connection_attempts); |
224 } | 278 } |
225 | 279 |
226 DomainReliabilityMonitor::RequestInfo::~RequestInfo() {} | 280 DomainReliabilityMonitor::RequestInfo::~RequestInfo() {} |
227 | 281 |
228 bool DomainReliabilityMonitor::RequestInfo::AccessedNetwork() const { | 282 // static |
229 return status.status() != net::URLRequestStatus::CANCELED && | 283 bool DomainReliabilityMonitor::RequestInfo::ShouldReportRequest( |
230 response_info.network_accessed; | 284 const DomainReliabilityMonitor::RequestInfo& request) { |
| 285 // Don't report requests for Domain Reliability uploads or that weren't |
| 286 // supposed to send cookies. |
| 287 if (request.is_upload) |
| 288 return false; |
| 289 if (request.load_flags & net::LOAD_DO_NOT_SEND_COOKIES) |
| 290 return false; |
| 291 // Report requests that accessed the network or failed with an error code |
| 292 // that Domain Reliability is interested in. |
| 293 if (request.response_info.network_accessed) |
| 294 return true; |
| 295 if (URLRequestStatusToNetError(request.status) != net::OK) |
| 296 return true; |
| 297 return false; |
231 } | 298 } |
232 | 299 |
233 void DomainReliabilityMonitor::OnRequestLegComplete( | 300 void DomainReliabilityMonitor::OnRequestLegComplete( |
234 const RequestInfo& request) { | 301 const RequestInfo& request) { |
235 // Check these again because unit tests call this directly. | 302 // Check these again because unit tests call this directly. |
236 DCHECK(OnNetworkThread()); | 303 DCHECK(OnNetworkThread()); |
237 DCHECK(discard_uploads_set_); | 304 DCHECK(discard_uploads_set_); |
238 | 305 |
| 306 if (!RequestInfo::ShouldReportRequest(request)) |
| 307 return; |
| 308 |
239 int response_code; | 309 int response_code; |
240 if (request.response_info.headers.get()) | 310 if (request.response_info.headers.get()) |
241 response_code = request.response_info.headers->response_code(); | 311 response_code = request.response_info.headers->response_code(); |
242 else | 312 else |
243 response_code = -1; | 313 response_code = -1; |
244 std::string beacon_status; | |
245 | 314 |
246 int error_code = net::OK; | 315 net::IPEndPoint url_request_endpoint; |
247 if (request.status.status() == net::URLRequestStatus::FAILED) | 316 // If response was cached, socket address will be from the serialized |
248 error_code = request.status.error(); | 317 // response info in the cache, so don't report it. |
249 | 318 // TODO(ttuttle): Plumb out the "current" socket address so we can always |
250 // Ignore requests where: | 319 // report it. |
251 // 1. The request did not access the network. | 320 if (!request.response_info.was_cached && |
252 // 2. The request is not supposed to send cookies (to avoid associating the | 321 !request.response_info.was_fetched_via_proxy) { |
253 // request with any potentially unique data in the config). | 322 ConvertHostPortPairToIPEndPoint(request.response_info.socket_address, |
254 // 3. The request was itself a Domain Reliability upload (to avoid loops). | 323 &url_request_endpoint); |
255 // 4. There is no matching beacon status for the error or HTTP response code | |
256 // (to avoid leaking network-local errors). | |
257 if (!request.AccessedNetwork() || | |
258 (request.load_flags & net::LOAD_DO_NOT_SEND_COOKIES) || | |
259 request.is_upload || | |
260 !GetDomainReliabilityBeaconStatus( | |
261 error_code, response_code, &beacon_status)) { | |
262 return; | |
263 } | 324 } |
264 | 325 |
| 326 net::ConnectionAttempt url_request_attempt( |
| 327 url_request_endpoint, URLRequestStatusToNetError(request.status)); |
| 328 |
265 DomainReliabilityBeacon beacon; | 329 DomainReliabilityBeacon beacon; |
266 beacon.status = beacon_status; | |
267 beacon.chrome_error = error_code; | |
268 // If the response was cached, the socket address was the address that the | |
269 // response was originally received from, so it shouldn't be copied into the | |
270 // beacon. | |
271 // | |
272 // TODO(ttuttle): Wire up a way to get the real socket address in that case. | |
273 if (!request.response_info.was_cached && | |
274 !request.response_info.was_fetched_via_proxy) { | |
275 beacon.server_ip = request.response_info.socket_address.host(); | |
276 } | |
277 beacon.protocol = GetDomainReliabilityProtocol( | 330 beacon.protocol = GetDomainReliabilityProtocol( |
278 request.response_info.connection_info, | 331 request.response_info.connection_info, |
279 request.response_info.ssl_info.is_valid()); | 332 request.response_info.ssl_info.is_valid()); |
280 beacon.http_response_code = response_code; | 333 beacon.http_response_code = response_code; |
281 beacon.start_time = request.load_timing_info.request_start; | 334 beacon.start_time = request.load_timing_info.request_start; |
282 beacon.elapsed = time_->NowTicks() - beacon.start_time; | 335 beacon.elapsed = time_->NowTicks() - beacon.start_time; |
283 beacon.was_proxied = request.response_info.was_fetched_via_proxy; | 336 beacon.was_proxied = request.response_info.was_fetched_via_proxy; |
284 beacon.domain = request.url.host(); | 337 beacon.domain = request.url.host(); |
| 338 |
| 339 // This is not foolproof -- it's possible that we'll see the same error twice |
| 340 // (e.g. an SSL error during connection on one attempt, and then an error |
| 341 // that maps to the same code during a read). |
| 342 // TODO(ttuttle): Find a way for this code to reliably tell whether we |
| 343 // eventually established a connection or not. |
| 344 bool url_request_attempt_is_duplicate = false; |
| 345 for (const auto& attempt : request.connection_attempts) { |
| 346 if (attempt.result == url_request_attempt.result) |
| 347 url_request_attempt_is_duplicate = true; |
| 348 if (!UpdateBeaconFromAttempt(&beacon, attempt)) |
| 349 continue; |
| 350 context_manager_.RouteBeacon(request.url, beacon); |
| 351 } |
| 352 |
| 353 if (url_request_attempt_is_duplicate) |
| 354 return; |
| 355 if (!UpdateBeaconFromAttempt(&beacon, url_request_attempt)) |
| 356 return; |
285 context_manager_.RouteBeacon(request.url, beacon); | 357 context_manager_.RouteBeacon(request.url, beacon); |
286 } | 358 } |
287 | 359 |
288 base::WeakPtr<DomainReliabilityMonitor> | 360 base::WeakPtr<DomainReliabilityMonitor> |
289 DomainReliabilityMonitor::MakeWeakPtr() { | 361 DomainReliabilityMonitor::MakeWeakPtr() { |
290 return weak_factory_.GetWeakPtr(); | 362 return weak_factory_.GetWeakPtr(); |
291 } | 363 } |
292 | 364 |
293 } // namespace domain_reliability | 365 } // namespace domain_reliability |
OLD | NEW |