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 : time_(new ActualTime()),
26 upload_reporter_string_(upload_reporter_string),
28 DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()),
29 dispatcher_(time_.get()),
30 pref_task_runner_(pref_thread),
31 network_task_runner_(network_thread),
32 moved_to_network_thread_(false),
33 discard_uploads_set_(false),
35 DCHECK(OnPrefThread());
36 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
39 DomainReliabilityMonitor::DomainReliabilityMonitor(
40 const std::string& upload_reporter_string,
41 scoped_refptr<base::SingleThreadTaskRunner> pref_thread,
42 scoped_refptr<base::SingleThreadTaskRunner> network_thread,
43 scoped_ptr<MockableTime> time)
45 upload_reporter_string_(upload_reporter_string),
47 DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()),
48 dispatcher_(time_.get()),
49 pref_task_runner_(pref_thread),
50 network_task_runner_(network_thread),
51 moved_to_network_thread_(false),
52 discard_uploads_set_(false),
54 DCHECK(OnPrefThread());
55 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
58 DomainReliabilityMonitor::~DomainReliabilityMonitor() {
59 if (moved_to_network_thread_)
60 DCHECK(OnNetworkThread());
62 DCHECK(OnPrefThread());
65 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
68 void DomainReliabilityMonitor::MoveToNetworkThread() {
69 DCHECK(OnPrefThread());
70 DCHECK(!moved_to_network_thread_);
72 moved_to_network_thread_ = true;
75 void DomainReliabilityMonitor::InitURLRequestContext(
76 net::URLRequestContext* url_request_context) {
77 DCHECK(OnNetworkThread());
78 DCHECK(moved_to_network_thread_);
80 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
81 new net::TrivialURLRequestContextGetter(url_request_context,
82 network_task_runner_);
83 InitURLRequestContext(url_request_context_getter);
86 void DomainReliabilityMonitor::InitURLRequestContext(
87 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) {
88 DCHECK(OnNetworkThread());
89 DCHECK(moved_to_network_thread_);
91 // Make sure the URLRequestContext actually lives on what was declared to be
92 // the network thread.
93 DCHECK(url_request_context_getter->GetNetworkTaskRunner()->
94 RunsTasksOnCurrentThread());
96 uploader_ = DomainReliabilityUploader::Create(url_request_context_getter);
99 void DomainReliabilityMonitor::AddBakedInConfigs() {
100 DCHECK(OnNetworkThread());
101 DCHECK(moved_to_network_thread_);
103 base::Time now = base::Time::Now();
104 for (size_t i = 0; kBakedInJsonConfigs[i]; ++i) {
105 std::string json(kBakedInJsonConfigs[i]);
106 scoped_ptr<const DomainReliabilityConfig> config =
107 DomainReliabilityConfig::FromJSON(json);
108 if (config && config->IsExpired(now)) {
109 LOG(WARNING) << "Baked-in Domain Reliability config for "
110 << config->domain << " is expired.";
113 AddContext(config.Pass());
117 void DomainReliabilityMonitor::SetDiscardUploads(bool discard_uploads) {
118 DCHECK(OnNetworkThread());
119 DCHECK(moved_to_network_thread_);
122 uploader_->set_discard_uploads(discard_uploads);
123 discard_uploads_set_ = true;
126 void DomainReliabilityMonitor::OnBeforeRedirect(net::URLRequest* request) {
127 DCHECK(OnNetworkThread());
128 DCHECK(discard_uploads_set_);
130 // Record the redirect itself in addition to the final request.
131 OnRequestLegComplete(RequestInfo(*request));
134 void DomainReliabilityMonitor::OnCompleted(net::URLRequest* request,
136 DCHECK(OnNetworkThread());
137 DCHECK(discard_uploads_set_);
141 RequestInfo request_info(*request);
142 if (request_info.AccessedNetwork()) {
143 OnRequestLegComplete(request_info);
144 // A request was just using the network, so now is a good time to run any
145 // pending and eligible uploads.
146 dispatcher_.RunEligibleTasks();
150 void DomainReliabilityMonitor::OnNetworkChanged(
151 net::NetworkChangeNotifier::ConnectionType type) {
152 last_network_change_time_ = time_->NowTicks();
155 void DomainReliabilityMonitor::ClearBrowsingData(
156 DomainReliabilityClearMode mode) {
157 DCHECK(OnNetworkThread());
160 case CLEAR_BEACONS: {
161 ContextMap::const_iterator it;
162 for (it = contexts_.begin(); it != contexts_.end(); ++it)
163 it->second->ClearBeacons();
174 scoped_ptr<base::Value> DomainReliabilityMonitor::GetWebUIData() const {
175 DCHECK(OnNetworkThread());
177 base::ListValue* contexts_value = new base::ListValue();
178 for (ContextMap::const_iterator it = contexts_.begin();
179 it != contexts_.end();
181 contexts_value->Append(it->second->GetWebUIData().release());
184 base::DictionaryValue* data_value = new base::DictionaryValue();
185 data_value->Set("contexts", contexts_value);
187 return scoped_ptr<base::Value>(data_value);
190 DomainReliabilityContext* DomainReliabilityMonitor::AddContextForTesting(
191 scoped_ptr<const DomainReliabilityConfig> config) {
192 DCHECK(OnNetworkThread());
194 return AddContext(config.Pass());
197 DomainReliabilityMonitor::RequestInfo::RequestInfo() {}
199 DomainReliabilityMonitor::RequestInfo::RequestInfo(
200 const net::URLRequest& request)
201 : url(request.url()),
202 status(request.status()),
203 response_info(request.response_info()),
204 load_flags(request.load_flags()),
205 is_upload(DomainReliabilityUploader::URLRequestIsUpload(request)) {
206 request.GetLoadTimingInfo(&load_timing_info);
209 DomainReliabilityMonitor::RequestInfo::~RequestInfo() {}
211 bool DomainReliabilityMonitor::RequestInfo::AccessedNetwork() const {
212 return status.status() != net::URLRequestStatus::CANCELED &&
213 response_info.network_accessed;
216 DomainReliabilityContext* DomainReliabilityMonitor::AddContext(
217 scoped_ptr<const DomainReliabilityConfig> config) {
218 DCHECK(OnNetworkThread());
220 DCHECK(config->IsValid());
222 // Grab a copy of the domain before transferring ownership of |config|.
223 std::string domain = config->domain;
225 DomainReliabilityContext* context =
226 new DomainReliabilityContext(time_.get(),
228 upload_reporter_string_,
229 &last_network_change_time_,
234 std::pair<ContextMap::iterator, bool> map_it =
235 contexts_.insert(make_pair(domain, context));
236 // Make sure the domain wasn't already in the map.
237 DCHECK(map_it.second);
239 return map_it.first->second;
242 void DomainReliabilityMonitor::ClearContexts() {
243 STLDeleteContainerPairSecondPointers(
244 contexts_.begin(), contexts_.end());
248 void DomainReliabilityMonitor::OnRequestLegComplete(
249 const RequestInfo& request) {
250 // Check these again because unit tests call this directly.
251 DCHECK(OnNetworkThread());
252 DCHECK(discard_uploads_set_);
255 if (request.response_info.headers.get())
256 response_code = request.response_info.headers->response_code();
259 std::string beacon_status;
261 int error_code = net::OK;
262 if (request.status.status() == net::URLRequestStatus::FAILED)
263 error_code = request.status.error();
265 DomainReliabilityContext* context = GetContextForHost(request.url.host());
267 // Ignore requests where:
268 // 1. There is no context for the request host.
269 // 2. The request did not access the network.
270 // 3. The request is not supposed to send cookies (to avoid associating the
271 // request with any potentially unique data in the config).
272 // 4. The request was itself a Domain Reliability upload (to avoid loops).
273 // 5. There is no defined beacon status for the error or HTTP response code
274 // (to avoid leaking network-local errors).
276 !request.AccessedNetwork() ||
277 (request.load_flags & net::LOAD_DO_NOT_SEND_COOKIES) ||
279 !GetDomainReliabilityBeaconStatus(
280 error_code, response_code, &beacon_status)) {
284 DomainReliabilityBeacon beacon;
285 beacon.status = beacon_status;
286 beacon.chrome_error = error_code;
287 if (!request.response_info.was_fetched_via_proxy)
288 beacon.server_ip = request.response_info.socket_address.host();
290 beacon.server_ip.clear();
291 beacon.protocol = GetDomainReliabilityProtocol(
292 request.response_info.connection_info,
293 request.response_info.ssl_info.is_valid());
294 beacon.http_response_code = response_code;
295 beacon.start_time = request.load_timing_info.request_start;
296 beacon.elapsed = time_->NowTicks() - beacon.start_time;
297 beacon.domain = request.url.host();
298 context->OnBeacon(request.url, beacon);
301 // TODO(ttuttle): Keep a separate wildcard_contexts_ map to avoid having to
302 // prepend '*.' to domains.
303 DomainReliabilityContext* DomainReliabilityMonitor::GetContextForHost(
304 const std::string& host) const {
305 DCHECK(OnNetworkThread());
307 ContextMap::const_iterator context_it;
309 context_it = contexts_.find(host);
310 if (context_it != contexts_.end())
311 return context_it->second;
313 std::string host_with_asterisk = "*." + host;
314 context_it = contexts_.find(host_with_asterisk);
315 if (context_it != contexts_.end())
316 return context_it->second;
318 size_t dot_pos = host.find('.');
319 if (dot_pos == std::string::npos)
322 // TODO(ttuttle): Make sure parent is not in PSL before using.
324 std::string parent_with_asterisk = "*." + host.substr(dot_pos + 1);
325 context_it = contexts_.find(parent_with_asterisk);
326 if (context_it != contexts_.end())
327 return context_it->second;
332 base::WeakPtr<DomainReliabilityMonitor>
333 DomainReliabilityMonitor::MakeWeakPtr() {
334 return weak_factory_.GetWeakPtr();
337 } // namespace domain_reliability