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/message_loop/message_loop.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/task_runner.h"
12 #include "base/threading/thread_checker.h"
13 #include "base/time/time.h"
14 #include "components/domain_reliability/baked_in_configs.h"
15 #include "net/base/load_flags.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/url_request/url_request.h"
18 #include "net/url_request/url_request_context.h"
19 #include "net/url_request/url_request_context_getter.h"
21 namespace domain_reliability {
23 DomainReliabilityMonitor::DomainReliabilityMonitor(
24 const std::string& upload_reporter_string)
25 : time_(new ActualTime()),
26 upload_reporter_string_(upload_reporter_string),
28 DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()),
29 dispatcher_(time_.get()),
31 cleared_mode_(MAX_CLEAR_MODE),
32 weak_factory_(this) {}
34 DomainReliabilityMonitor::DomainReliabilityMonitor(
35 const std::string& upload_reporter_string,
36 scoped_ptr<MockableTime> time)
38 upload_reporter_string_(upload_reporter_string),
40 DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()),
41 dispatcher_(time_.get()),
43 cleared_mode_(MAX_CLEAR_MODE),
44 weak_factory_(this) {}
46 DomainReliabilityMonitor::~DomainReliabilityMonitor() {
50 void DomainReliabilityMonitor::Init(
51 net::URLRequestContext* url_request_context,
52 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
53 DCHECK(!thread_checker_);
55 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
56 new net::TrivialURLRequestContextGetter(url_request_context,
58 Init(url_request_context_getter);
61 void DomainReliabilityMonitor::Init(
62 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) {
63 DCHECK(!thread_checker_);
65 DCHECK(url_request_context_getter->GetNetworkTaskRunner()->
66 RunsTasksOnCurrentThread());
68 uploader_ = DomainReliabilityUploader::Create(url_request_context_getter);
69 thread_checker_.reset(new base::ThreadChecker());
72 void DomainReliabilityMonitor::AddBakedInConfigs() {
73 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
74 base::Time now = base::Time::Now();
75 for (size_t i = 0; kBakedInJsonConfigs[i]; ++i) {
76 std::string json(kBakedInJsonConfigs[i]);
77 scoped_ptr<const DomainReliabilityConfig> config =
78 DomainReliabilityConfig::FromJSON(json);
79 if (config && config->IsExpired(now)) {
80 LOG(WARNING) << "Baked-in Domain Reliability config for "
81 << config->domain << " is expired.";
84 AddContext(config.Pass());
88 void DomainReliabilityMonitor::OnBeforeRedirect(net::URLRequest* request) {
89 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
90 // Record the redirect itself in addition to the final request.
91 OnRequestLegComplete(RequestInfo(*request));
94 void DomainReliabilityMonitor::OnCompleted(net::URLRequest* request,
96 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
99 RequestInfo request_info(*request);
100 if (request_info.AccessedNetwork()) {
101 OnRequestLegComplete(request_info);
102 // A request was just using the network, so now is a good time to run any
103 // pending and eligible uploads.
104 dispatcher_.RunEligibleTasks();
108 void DomainReliabilityMonitor::ClearBrowsingData(
109 DomainReliabilityClearMode mode) {
110 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
113 cleared_mode_ = mode;
116 case CLEAR_BEACONS: {
117 ContextMap::const_iterator it;
118 for (it = contexts_.begin(); it != contexts_.end(); ++it)
119 it->second->ClearBeacons();
130 DomainReliabilityContext* DomainReliabilityMonitor::AddContextForTesting(
131 scoped_ptr<const DomainReliabilityConfig> config) {
132 DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
133 return AddContext(config.Pass());
136 DomainReliabilityMonitor::RequestInfo::RequestInfo() {}
138 DomainReliabilityMonitor::RequestInfo::RequestInfo(
139 const net::URLRequest& request)
140 : url(request.url()),
141 status(request.status()),
142 response_info(request.response_info()),
143 load_flags(request.load_flags()),
144 is_upload(DomainReliabilityUploader::URLRequestIsUpload(request)) {
145 request.GetLoadTimingInfo(&load_timing_info);
148 DomainReliabilityMonitor::RequestInfo::~RequestInfo() {}
150 bool DomainReliabilityMonitor::RequestInfo::AccessedNetwork() const {
151 return status.status() != net::URLRequestStatus::CANCELED &&
152 response_info.network_accessed;
155 DomainReliabilityContext* DomainReliabilityMonitor::AddContext(
156 scoped_ptr<const DomainReliabilityConfig> config) {
158 DCHECK(config->IsValid());
160 // Grab a copy of the domain before transferring ownership of |config|.
161 std::string domain = config->domain;
163 DomainReliabilityContext* context =
164 new DomainReliabilityContext(time_.get(),
166 upload_reporter_string_,
171 std::pair<ContextMap::iterator, bool> map_it =
172 contexts_.insert(make_pair(domain, context));
173 // Make sure the domain wasn't already in the map.
174 DCHECK(map_it.second);
176 return map_it.first->second;
179 void DomainReliabilityMonitor::ClearContexts() {
180 STLDeleteContainerPairSecondPointers(
181 contexts_.begin(), contexts_.end());
185 void DomainReliabilityMonitor::OnRequestLegComplete(
186 const RequestInfo& request) {
188 if (request.response_info.headers)
189 response_code = request.response_info.headers->response_code();
192 ContextMap::iterator context_it;
193 std::string beacon_status;
195 int error_code = net::OK;
196 if (request.status.status() == net::URLRequestStatus::FAILED)
197 error_code = request.status.error();
199 // Ignore requests where:
200 // 1. There is no context for the request host.
201 // 2. The request did not access the network.
202 // 3. The request is not supposed to send cookies (to avoid associating the
203 // request with any potentially unique data in the config).
204 // 4. The request was itself a Domain Reliability upload (to avoid loops).
205 // 5. There is no defined beacon status for the error or HTTP response code
206 // (to avoid leaking network-local errors).
207 if ((context_it = contexts_.find(request.url.host())) == contexts_.end() ||
208 !request.AccessedNetwork() ||
209 (request.load_flags & net::LOAD_DO_NOT_SEND_COOKIES) ||
211 !GetDomainReliabilityBeaconStatus(
212 error_code, response_code, &beacon_status)) {
216 DomainReliabilityBeacon beacon;
217 beacon.status = beacon_status;
218 beacon.chrome_error = error_code;
219 if (!request.response_info.was_fetched_via_proxy)
220 beacon.server_ip = request.response_info.socket_address.host();
222 beacon.server_ip.clear();
223 beacon.http_response_code = response_code;
224 beacon.start_time = request.load_timing_info.request_start;
225 beacon.elapsed = time_->NowTicks() - beacon.start_time;
226 context_it->second->OnBeacon(request.url, beacon);
229 base::WeakPtr<DomainReliabilityMonitor>
230 DomainReliabilityMonitor::MakeWeakPtr() {
231 return weak_factory_.GetWeakPtr();
234 } // namespace domain_reliability