Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / components / domain_reliability / monitor.cc
blob7f79ce5aabe57d8390cd22d7600be40dbed609d1
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/single_thread_task_runner.h"
10 #include "base/task_runner.h"
11 #include "base/time/time.h"
12 #include "components/domain_reliability/baked_in_configs.h"
13 #include "net/base/load_flags.h"
14 #include "net/http/http_response_headers.h"
15 #include "net/url_request/url_request.h"
16 #include "net/url_request/url_request_context.h"
17 #include "net/url_request/url_request_context_getter.h"
19 namespace domain_reliability {
21 DomainReliabilityMonitor::DomainReliabilityMonitor(
22 const std::string& upload_reporter_string,
23 scoped_refptr<base::SingleThreadTaskRunner> pref_thread,
24 scoped_refptr<base::SingleThreadTaskRunner> network_thread,
25 PrefService* local_state_pref_service,
26 const char* reporting_pref_name)
27 : time_(new ActualTime()),
28 upload_reporter_string_(upload_reporter_string),
29 scheduler_params_(
30 DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()),
31 dispatcher_(time_.get()),
32 pref_task_runner_(pref_thread),
33 network_task_runner_(network_thread),
34 moved_to_network_thread_(false),
35 weak_factory_(this) {
36 DCHECK(OnPrefThread());
37 InitReportingPref(local_state_pref_service, reporting_pref_name);
40 DomainReliabilityMonitor::DomainReliabilityMonitor(
41 const std::string& upload_reporter_string,
42 scoped_refptr<base::SingleThreadTaskRunner> pref_thread,
43 scoped_refptr<base::SingleThreadTaskRunner> network_thread,
44 PrefService* local_state_pref_service,
45 const char* reporting_pref_name,
46 scoped_ptr<MockableTime> time)
47 : time_(time.Pass()),
48 upload_reporter_string_(upload_reporter_string),
49 scheduler_params_(
50 DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()),
51 dispatcher_(time_.get()),
52 pref_task_runner_(pref_thread),
53 network_task_runner_(network_thread),
54 moved_to_network_thread_(false),
55 weak_factory_(this) {
56 DCHECK(OnPrefThread());
57 InitReportingPref(local_state_pref_service, reporting_pref_name);
60 DomainReliabilityMonitor::~DomainReliabilityMonitor() {
61 if (moved_to_network_thread_)
62 DCHECK(OnNetworkThread());
63 else
64 DCHECK(OnPrefThread());
66 ClearContexts();
69 void DomainReliabilityMonitor::MoveToNetworkThread() {
70 DCHECK(OnPrefThread());
71 DCHECK(!moved_to_network_thread_);
73 reporting_pref_.MoveToThread(network_task_runner_);
74 moved_to_network_thread_ = true;
77 void DomainReliabilityMonitor::DestroyReportingPref() {
78 DCHECK(OnPrefThread());
80 reporting_pref_.Destroy();
83 void DomainReliabilityMonitor::InitURLRequestContext(
84 net::URLRequestContext* url_request_context) {
85 DCHECK(OnNetworkThread());
86 DCHECK(moved_to_network_thread_);
88 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
89 new net::TrivialURLRequestContextGetter(url_request_context,
90 network_task_runner_);
91 InitURLRequestContext(url_request_context_getter);
94 void DomainReliabilityMonitor::InitURLRequestContext(
95 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) {
96 DCHECK(OnNetworkThread());
97 DCHECK(moved_to_network_thread_);
99 // Make sure the URLRequestContext actually lives on what was declared to be
100 // the network thread.
101 DCHECK(url_request_context_getter->GetNetworkTaskRunner()->
102 RunsTasksOnCurrentThread());
104 uploader_ = DomainReliabilityUploader::Create(url_request_context_getter);
105 // Make sure the uploader is sending or discarding uploads according to pref.
106 OnReportingPrefChanged();
109 void DomainReliabilityMonitor::AddBakedInConfigs() {
110 DCHECK(OnNetworkThread());
112 base::Time now = base::Time::Now();
113 for (size_t i = 0; kBakedInJsonConfigs[i]; ++i) {
114 std::string json(kBakedInJsonConfigs[i]);
115 scoped_ptr<const DomainReliabilityConfig> config =
116 DomainReliabilityConfig::FromJSON(json);
117 if (config && config->IsExpired(now)) {
118 LOG(WARNING) << "Baked-in Domain Reliability config for "
119 << config->domain << " is expired.";
120 continue;
122 AddContext(config.Pass());
126 void DomainReliabilityMonitor::OnBeforeRedirect(net::URLRequest* request) {
127 DCHECK(OnNetworkThread());
129 // Record the redirect itself in addition to the final request.
130 OnRequestLegComplete(RequestInfo(*request));
133 void DomainReliabilityMonitor::OnCompleted(net::URLRequest* request,
134 bool started) {
135 DCHECK(OnNetworkThread());
137 if (!started)
138 return;
139 RequestInfo request_info(*request);
140 if (request_info.AccessedNetwork()) {
141 OnRequestLegComplete(request_info);
142 // A request was just using the network, so now is a good time to run any
143 // pending and eligible uploads.
144 dispatcher_.RunEligibleTasks();
148 void DomainReliabilityMonitor::ClearBrowsingData(
149 DomainReliabilityClearMode mode) {
150 DCHECK(OnNetworkThread());
152 switch (mode) {
153 case CLEAR_BEACONS: {
154 ContextMap::const_iterator it;
155 for (it = contexts_.begin(); it != contexts_.end(); ++it)
156 it->second->ClearBeacons();
157 break;
159 case CLEAR_CONTEXTS:
160 ClearContexts();
161 break;
162 case MAX_CLEAR_MODE:
163 NOTREACHED();
167 scoped_ptr<base::Value> DomainReliabilityMonitor::GetWebUIData() const {
168 DCHECK(OnNetworkThread());
170 base::ListValue* contexts_value = new base::ListValue();
171 for (ContextMap::const_iterator it = contexts_.begin();
172 it != contexts_.end();
173 ++it) {
174 contexts_value->Append(it->second->GetWebUIData().release());
177 base::DictionaryValue* data_value = new base::DictionaryValue();
178 data_value->Set("contexts", contexts_value);
180 return scoped_ptr<base::Value>(data_value);
183 DomainReliabilityContext* DomainReliabilityMonitor::AddContextForTesting(
184 scoped_ptr<const DomainReliabilityConfig> config) {
185 DCHECK(OnNetworkThread());
187 return AddContext(config.Pass());
190 DomainReliabilityMonitor::RequestInfo::RequestInfo() {}
192 DomainReliabilityMonitor::RequestInfo::RequestInfo(
193 const net::URLRequest& request)
194 : url(request.url()),
195 status(request.status()),
196 response_info(request.response_info()),
197 load_flags(request.load_flags()),
198 is_upload(DomainReliabilityUploader::URLRequestIsUpload(request)) {
199 request.GetLoadTimingInfo(&load_timing_info);
202 DomainReliabilityMonitor::RequestInfo::~RequestInfo() {}
204 bool DomainReliabilityMonitor::RequestInfo::AccessedNetwork() const {
205 return status.status() != net::URLRequestStatus::CANCELED &&
206 response_info.network_accessed;
209 DomainReliabilityContext* DomainReliabilityMonitor::AddContext(
210 scoped_ptr<const DomainReliabilityConfig> config) {
211 DCHECK(OnNetworkThread());
212 DCHECK(config);
213 DCHECK(config->IsValid());
215 // Grab a copy of the domain before transferring ownership of |config|.
216 std::string domain = config->domain;
218 DomainReliabilityContext* context =
219 new DomainReliabilityContext(time_.get(),
220 scheduler_params_,
221 upload_reporter_string_,
222 &dispatcher_,
223 uploader_.get(),
224 config.Pass());
226 std::pair<ContextMap::iterator, bool> map_it =
227 contexts_.insert(make_pair(domain, context));
228 // Make sure the domain wasn't already in the map.
229 DCHECK(map_it.second);
231 return map_it.first->second;
234 void DomainReliabilityMonitor::ClearContexts() {
235 STLDeleteContainerPairSecondPointers(
236 contexts_.begin(), contexts_.end());
237 contexts_.clear();
240 void DomainReliabilityMonitor::OnRequestLegComplete(
241 const RequestInfo& request) {
242 int response_code;
243 if (request.response_info.headers.get())
244 response_code = request.response_info.headers->response_code();
245 else
246 response_code = -1;
247 std::string beacon_status;
249 int error_code = net::OK;
250 if (request.status.status() == net::URLRequestStatus::FAILED)
251 error_code = request.status.error();
253 DomainReliabilityContext* context = GetContextForHost(request.url.host());
255 // Ignore requests where:
256 // 1. There is no context for the request host.
257 // 2. The request did not access the network.
258 // 3. The request is not supposed to send cookies (to avoid associating the
259 // request with any potentially unique data in the config).
260 // 4. The request was itself a Domain Reliability upload (to avoid loops).
261 // 5. There is no defined beacon status for the error or HTTP response code
262 // (to avoid leaking network-local errors).
263 if (!context ||
264 !request.AccessedNetwork() ||
265 (request.load_flags & net::LOAD_DO_NOT_SEND_COOKIES) ||
266 request.is_upload ||
267 !GetDomainReliabilityBeaconStatus(
268 error_code, response_code, &beacon_status)) {
269 return;
272 DomainReliabilityBeacon beacon;
273 beacon.status = beacon_status;
274 beacon.chrome_error = error_code;
275 if (!request.response_info.was_fetched_via_proxy)
276 beacon.server_ip = request.response_info.socket_address.host();
277 else
278 beacon.server_ip.clear();
279 beacon.protocol = GetDomainReliabilityProtocol(
280 request.response_info.connection_info,
281 request.response_info.ssl_info.is_valid());
282 beacon.http_response_code = response_code;
283 beacon.start_time = request.load_timing_info.request_start;
284 beacon.elapsed = time_->NowTicks() - beacon.start_time;
285 context->OnBeacon(request.url, beacon);
288 void DomainReliabilityMonitor::InitReportingPref(
289 PrefService* local_state_pref_service,
290 const char* reporting_pref_name) {
291 reporting_pref_.Init(
292 reporting_pref_name,
293 local_state_pref_service,
294 base::Bind(&DomainReliabilityMonitor::OnReportingPrefChanged,
295 base::Unretained(this)));
298 void DomainReliabilityMonitor::OnReportingPrefChanged() {
299 DCHECK(OnNetworkThread());
301 // When metrics reporting is disabled, discard Domain Reliability uploads.
302 if (uploader_)
303 uploader_->set_discard_uploads(!*reporting_pref_);
306 // TODO(ttuttle): Keep a separate wildcard_contexts_ map to avoid having to
307 // prepend '*.' to domains.
308 DomainReliabilityContext* DomainReliabilityMonitor::GetContextForHost(
309 const std::string& host) const {
310 DCHECK(OnNetworkThread());
312 ContextMap::const_iterator context_it;
314 context_it = contexts_.find(host);
315 if (context_it != contexts_.end())
316 return context_it->second;
318 std::string host_with_asterisk = "*." + host;
319 context_it = contexts_.find(host_with_asterisk);
320 if (context_it != contexts_.end())
321 return context_it->second;
323 size_t dot_pos = host.find('.');
324 if (dot_pos == std::string::npos)
325 return NULL;
327 // TODO(ttuttle): Make sure parent is not in PSL before using.
329 std::string parent_with_asterisk = "*." + host.substr(dot_pos + 1);
330 context_it = contexts_.find(parent_with_asterisk);
331 if (context_it != contexts_.end())
332 return context_it->second;
334 return NULL;
337 base::WeakPtr<DomainReliabilityMonitor>
338 DomainReliabilityMonitor::MakeWeakPtr() {
339 return weak_factory_.GetWeakPtr();
342 } // namespace domain_reliability