Roll src/third_party/WebKit 9f7fb92:f103b33 (svn 202621:202622)
[chromium-blink-merge.git] / components / domain_reliability / monitor.cc
blob014f34de048464c483d32a7e7e3e9ee42660c050
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
3 // found in the LICENSE file.
5 #include "components/domain_reliability/monitor.h"
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/profiler/scoped_tracker.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/task_runner.h"
12 #include "base/time/time.h"
13 #include "components/domain_reliability/baked_in_configs.h"
14 #include "net/base/ip_endpoint.h"
15 #include "net/base/load_flags.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/net_util.h"
18 #include "net/http/http_response_headers.h"
19 #include "net/url_request/url_request.h"
20 #include "net/url_request/url_request_context.h"
21 #include "net/url_request/url_request_context_getter.h"
23 namespace domain_reliability {
25 namespace {
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;
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;
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;
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;
72 } // namespace
74 DomainReliabilityMonitor::DomainReliabilityMonitor(
75 const std::string& upload_reporter_string,
76 const scoped_refptr<base::SingleThreadTaskRunner>& pref_thread,
77 const scoped_refptr<base::SingleThreadTaskRunner>& network_thread)
78 : time_(new ActualTime()),
79 upload_reporter_string_(upload_reporter_string),
80 scheduler_params_(
81 DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()),
82 dispatcher_(time_.get()),
83 context_manager_(this),
84 pref_task_runner_(pref_thread),
85 network_task_runner_(network_thread),
86 moved_to_network_thread_(false),
87 discard_uploads_set_(false),
88 weak_factory_(this) {
89 DCHECK(OnPrefThread());
90 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
93 DomainReliabilityMonitor::DomainReliabilityMonitor(
94 const std::string& upload_reporter_string,
95 const scoped_refptr<base::SingleThreadTaskRunner>& pref_thread,
96 const scoped_refptr<base::SingleThreadTaskRunner>& network_thread,
97 scoped_ptr<MockableTime> time)
98 : time_(time.Pass()),
99 upload_reporter_string_(upload_reporter_string),
100 scheduler_params_(
101 DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()),
102 dispatcher_(time_.get()),
103 context_manager_(this),
104 pref_task_runner_(pref_thread),
105 network_task_runner_(network_thread),
106 moved_to_network_thread_(false),
107 discard_uploads_set_(false),
108 weak_factory_(this) {
109 DCHECK(OnPrefThread());
110 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
113 DomainReliabilityMonitor::~DomainReliabilityMonitor() {
114 if (moved_to_network_thread_)
115 DCHECK(OnNetworkThread());
116 else
117 DCHECK(OnPrefThread());
119 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
122 void DomainReliabilityMonitor::MoveToNetworkThread() {
123 DCHECK(OnPrefThread());
124 DCHECK(!moved_to_network_thread_);
126 moved_to_network_thread_ = true;
129 void DomainReliabilityMonitor::InitURLRequestContext(
130 net::URLRequestContext* url_request_context) {
131 DCHECK(OnNetworkThread());
132 DCHECK(moved_to_network_thread_);
134 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
135 new net::TrivialURLRequestContextGetter(url_request_context,
136 network_task_runner_);
137 InitURLRequestContext(url_request_context_getter);
140 void DomainReliabilityMonitor::InitURLRequestContext(
141 const scoped_refptr<net::URLRequestContextGetter>&
142 url_request_context_getter) {
143 DCHECK(OnNetworkThread());
144 DCHECK(moved_to_network_thread_);
146 // Make sure the URLRequestContext actually lives on what was declared to be
147 // the network thread.
148 DCHECK(url_request_context_getter->GetNetworkTaskRunner()->
149 RunsTasksOnCurrentThread());
151 uploader_ = DomainReliabilityUploader::Create(time_.get(),
152 url_request_context_getter);
155 void DomainReliabilityMonitor::AddBakedInConfigs() {
156 // TODO(ttuttle): Remove ScopedTracker below once crbug.com/436671 is fixed.
157 tracked_objects::ScopedTracker tracking_profile(
158 FROM_HERE_WITH_EXPLICIT_FUNCTION(
159 "436671 DomainReliabilityMonitor::AddBakedInConfigs"));
161 DCHECK(OnNetworkThread());
162 DCHECK(moved_to_network_thread_);
164 base::Time now = base::Time::Now();
165 for (size_t i = 0; kBakedInJsonConfigs[i]; ++i) {
166 base::StringPiece json(kBakedInJsonConfigs[i]);
167 scoped_ptr<const DomainReliabilityConfig> config =
168 DomainReliabilityConfig::FromJSON(json);
169 if (!config) {
170 continue;
171 } else if (config->IsExpired(now)) {
172 LOG(WARNING) << "Baked-in Domain Reliability config for "
173 << config->domain << " is expired.";
174 continue;
176 context_manager_.AddContextForConfig(config.Pass());
180 void DomainReliabilityMonitor::SetDiscardUploads(bool discard_uploads) {
181 DCHECK(OnNetworkThread());
182 DCHECK(moved_to_network_thread_);
183 DCHECK(uploader_);
185 uploader_->set_discard_uploads(discard_uploads);
186 discard_uploads_set_ = true;
189 void DomainReliabilityMonitor::OnBeforeRedirect(net::URLRequest* request) {
190 DCHECK(OnNetworkThread());
191 DCHECK(discard_uploads_set_);
193 // Record the redirect itself in addition to the final request.
194 OnRequestLegComplete(RequestInfo(*request));
197 void DomainReliabilityMonitor::OnCompleted(net::URLRequest* request,
198 bool started) {
199 DCHECK(OnNetworkThread());
200 DCHECK(discard_uploads_set_);
202 if (!started)
203 return;
204 RequestInfo request_info(*request);
205 OnRequestLegComplete(request_info);
207 if (request_info.response_info.network_accessed) {
208 // A request was just using the network, so now is a good time to run any
209 // pending and eligible uploads.
210 dispatcher_.RunEligibleTasks();
214 void DomainReliabilityMonitor::OnNetworkChanged(
215 net::NetworkChangeNotifier::ConnectionType type) {
216 last_network_change_time_ = time_->NowTicks();
219 void DomainReliabilityMonitor::ClearBrowsingData(
220 DomainReliabilityClearMode mode) {
221 DCHECK(OnNetworkThread());
223 switch (mode) {
224 case CLEAR_BEACONS:
225 context_manager_.ClearBeaconsInAllContexts();
226 break;
227 case CLEAR_CONTEXTS:
228 context_manager_.RemoveAllContexts();
229 break;
230 case MAX_CLEAR_MODE:
231 NOTREACHED();
235 scoped_ptr<base::Value> DomainReliabilityMonitor::GetWebUIData() const {
236 DCHECK(OnNetworkThread());
238 scoped_ptr<base::DictionaryValue> data_value(new base::DictionaryValue());
239 data_value->Set("contexts", context_manager_.GetWebUIData());
240 return data_value.Pass();
243 DomainReliabilityContext* DomainReliabilityMonitor::AddContextForTesting(
244 scoped_ptr<const DomainReliabilityConfig> config) {
245 DCHECK(OnNetworkThread());
247 return context_manager_.AddContextForConfig(config.Pass());
250 scoped_ptr<DomainReliabilityContext>
251 DomainReliabilityMonitor::CreateContextForConfig(
252 scoped_ptr<const DomainReliabilityConfig> config) {
253 DCHECK(OnNetworkThread());
254 DCHECK(config);
255 DCHECK(config->IsValid());
257 return make_scoped_ptr(new DomainReliabilityContext(
258 time_.get(),
259 scheduler_params_,
260 upload_reporter_string_,
261 &last_network_change_time_,
262 &dispatcher_,
263 uploader_.get(),
264 config.Pass()));
267 DomainReliabilityMonitor::RequestInfo::RequestInfo() {}
269 DomainReliabilityMonitor::RequestInfo::RequestInfo(
270 const net::URLRequest& request)
271 : url(request.url()),
272 status(request.status()),
273 response_info(request.response_info()),
274 load_flags(request.load_flags()),
275 is_upload(DomainReliabilityUploader::URLRequestIsUpload(request)) {
276 request.GetLoadTimingInfo(&load_timing_info);
277 request.GetConnectionAttempts(&connection_attempts);
280 DomainReliabilityMonitor::RequestInfo::~RequestInfo() {}
282 // static
283 bool DomainReliabilityMonitor::RequestInfo::ShouldReportRequest(
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;
300 void DomainReliabilityMonitor::OnRequestLegComplete(
301 const RequestInfo& request) {
302 // Check these again because unit tests call this directly.
303 DCHECK(OnNetworkThread());
304 DCHECK(discard_uploads_set_);
306 if (!RequestInfo::ShouldReportRequest(request))
307 return;
309 int response_code;
310 if (request.response_info.headers.get())
311 response_code = request.response_info.headers->response_code();
312 else
313 response_code = -1;
315 net::IPEndPoint url_request_endpoint;
316 // If response was cached, socket address will be from the serialized
317 // response info in the cache, so don't report it.
318 // TODO(ttuttle): Plumb out the "current" socket address so we can always
319 // report it.
320 if (!request.response_info.was_cached &&
321 !request.response_info.was_fetched_via_proxy) {
322 ConvertHostPortPairToIPEndPoint(request.response_info.socket_address,
323 &url_request_endpoint);
326 net::ConnectionAttempt url_request_attempt(
327 url_request_endpoint, URLRequestStatusToNetError(request.status));
329 DomainReliabilityBeacon beacon;
330 beacon.protocol = GetDomainReliabilityProtocol(
331 request.response_info.connection_info,
332 request.response_info.ssl_info.is_valid());
333 beacon.http_response_code = response_code;
334 beacon.start_time = request.load_timing_info.request_start;
335 beacon.elapsed = time_->NowTicks() - beacon.start_time;
336 beacon.was_proxied = request.response_info.was_fetched_via_proxy;
337 beacon.domain = request.url.host();
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);
353 if (url_request_attempt_is_duplicate)
354 return;
355 if (!UpdateBeaconFromAttempt(&beacon, url_request_attempt))
356 return;
357 context_manager_.RouteBeacon(request.url, beacon);
360 base::WeakPtr<DomainReliabilityMonitor>
361 DomainReliabilityMonitor::MakeWeakPtr() {
362 return weak_factory_.GetWeakPtr();
365 } // namespace domain_reliability