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/load_flags.h"
15 #include "net/http/http_response_headers.h"
16 #include "net/url_request/url_request.h"
17 #include "net/url_request/url_request_context.h"
18 #include "net/url_request/url_request_context_getter.h"
20 namespace domain_reliability
{
22 DomainReliabilityMonitor::DomainReliabilityMonitor(
23 const std::string
& upload_reporter_string
,
24 const scoped_refptr
<base::SingleThreadTaskRunner
>& pref_thread
,
25 const scoped_refptr
<base::SingleThreadTaskRunner
>& network_thread
)
26 : time_(new ActualTime()),
27 upload_reporter_string_(upload_reporter_string
),
29 DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()),
30 dispatcher_(time_
.get()),
31 context_manager_(this),
32 pref_task_runner_(pref_thread
),
33 network_task_runner_(network_thread
),
34 moved_to_network_thread_(false),
35 discard_uploads_set_(false),
37 DCHECK(OnPrefThread());
38 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
41 DomainReliabilityMonitor::DomainReliabilityMonitor(
42 const std::string
& upload_reporter_string
,
43 const scoped_refptr
<base::SingleThreadTaskRunner
>& pref_thread
,
44 const scoped_refptr
<base::SingleThreadTaskRunner
>& network_thread
,
45 scoped_ptr
<MockableTime
> time
)
47 upload_reporter_string_(upload_reporter_string
),
49 DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()),
50 dispatcher_(time_
.get()),
51 context_manager_(this),
52 pref_task_runner_(pref_thread
),
53 network_task_runner_(network_thread
),
54 moved_to_network_thread_(false),
55 discard_uploads_set_(false),
57 DCHECK(OnPrefThread());
58 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
61 DomainReliabilityMonitor::~DomainReliabilityMonitor() {
62 if (moved_to_network_thread_
)
63 DCHECK(OnNetworkThread());
65 DCHECK(OnPrefThread());
67 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
70 void DomainReliabilityMonitor::MoveToNetworkThread() {
71 DCHECK(OnPrefThread());
72 DCHECK(!moved_to_network_thread_
);
74 moved_to_network_thread_
= true;
77 void DomainReliabilityMonitor::InitURLRequestContext(
78 net::URLRequestContext
* url_request_context
) {
79 // TODO(vadimt): Remove ScopedTracker below once crbug.com/436671 is fixed.
80 tracked_objects::ScopedTracker
tracking_profile(
81 FROM_HERE_WITH_EXPLICIT_FUNCTION(
82 "436671 DomainReliabilityMonitor::InitURLRequestContext"));
84 DCHECK(OnNetworkThread());
85 DCHECK(moved_to_network_thread_
);
87 scoped_refptr
<net::URLRequestContextGetter
> url_request_context_getter
=
88 new net::TrivialURLRequestContextGetter(url_request_context
,
89 network_task_runner_
);
90 InitURLRequestContext(url_request_context_getter
);
93 void DomainReliabilityMonitor::InitURLRequestContext(
94 const scoped_refptr
<net::URLRequestContextGetter
>&
95 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(time_
.get(),
105 url_request_context_getter
);
108 void DomainReliabilityMonitor::AddBakedInConfigs() {
109 // TODO(vadimt): Remove ScopedTracker below once crbug.com/436671 is fixed.
110 tracked_objects::ScopedTracker
tracking_profile(
111 FROM_HERE_WITH_EXPLICIT_FUNCTION(
112 "436671 DomainReliabilityMonitor::AddBakedInConfigs"));
114 DCHECK(OnNetworkThread());
115 DCHECK(moved_to_network_thread_
);
117 base::Time now
= base::Time::Now();
118 for (size_t i
= 0; kBakedInJsonConfigs
[i
]; ++i
) {
119 base::StringPiece
json(kBakedInJsonConfigs
[i
]);
120 scoped_ptr
<const DomainReliabilityConfig
> config
=
121 DomainReliabilityConfig::FromJSON(json
);
124 } else if (config
->IsExpired(now
)) {
125 LOG(WARNING
) << "Baked-in Domain Reliability config for "
126 << config
->domain
<< " is expired.";
129 context_manager_
.AddContextForConfig(config
.Pass());
133 void DomainReliabilityMonitor::SetDiscardUploads(bool discard_uploads
) {
134 DCHECK(OnNetworkThread());
135 DCHECK(moved_to_network_thread_
);
138 uploader_
->set_discard_uploads(discard_uploads
);
139 discard_uploads_set_
= true;
142 void DomainReliabilityMonitor::OnBeforeRedirect(net::URLRequest
* request
) {
143 DCHECK(OnNetworkThread());
144 DCHECK(discard_uploads_set_
);
146 // Record the redirect itself in addition to the final request.
147 OnRequestLegComplete(RequestInfo(*request
));
150 void DomainReliabilityMonitor::OnCompleted(net::URLRequest
* request
,
152 DCHECK(OnNetworkThread());
153 DCHECK(discard_uploads_set_
);
157 RequestInfo
request_info(*request
);
158 if (request_info
.AccessedNetwork()) {
159 OnRequestLegComplete(request_info
);
160 // A request was just using the network, so now is a good time to run any
161 // pending and eligible uploads.
162 dispatcher_
.RunEligibleTasks();
166 void DomainReliabilityMonitor::OnNetworkChanged(
167 net::NetworkChangeNotifier::ConnectionType type
) {
168 last_network_change_time_
= time_
->NowTicks();
171 void DomainReliabilityMonitor::ClearBrowsingData(
172 DomainReliabilityClearMode mode
) {
173 DCHECK(OnNetworkThread());
177 context_manager_
.ClearBeaconsInAllContexts();
180 context_manager_
.RemoveAllContexts();
187 scoped_ptr
<base::Value
> DomainReliabilityMonitor::GetWebUIData() const {
188 DCHECK(OnNetworkThread());
190 scoped_ptr
<base::DictionaryValue
> data_value(new base::DictionaryValue());
191 data_value
->Set("contexts", context_manager_
.GetWebUIData());
192 return data_value
.Pass();
195 DomainReliabilityContext
* DomainReliabilityMonitor::AddContextForTesting(
196 scoped_ptr
<const DomainReliabilityConfig
> config
) {
197 DCHECK(OnNetworkThread());
199 // TODO(vadimt): Remove ScopedTracker below once crbug.com/436671 is fixed.
200 tracked_objects::ScopedTracker
tracking_profile(
201 FROM_HERE_WITH_EXPLICIT_FUNCTION(
202 "436671 DomainReliabilityConfig::AddContextForConfig"));
204 return context_manager_
.AddContextForConfig(config
.Pass());
207 scoped_ptr
<DomainReliabilityContext
>
208 DomainReliabilityMonitor::CreateContextForConfig(
209 scoped_ptr
<const DomainReliabilityConfig
> config
) {
210 DCHECK(OnNetworkThread());
212 DCHECK(config
->IsValid());
214 return make_scoped_ptr(new DomainReliabilityContext(
217 upload_reporter_string_
,
218 &last_network_change_time_
,
224 DomainReliabilityMonitor::RequestInfo::RequestInfo() {}
226 DomainReliabilityMonitor::RequestInfo::RequestInfo(
227 const net::URLRequest
& request
)
228 : url(request
.url()),
229 status(request
.status()),
230 response_info(request
.response_info()),
231 load_flags(request
.load_flags()),
232 is_upload(DomainReliabilityUploader::URLRequestIsUpload(request
)) {
233 request
.GetLoadTimingInfo(&load_timing_info
);
236 DomainReliabilityMonitor::RequestInfo::~RequestInfo() {}
238 bool DomainReliabilityMonitor::RequestInfo::AccessedNetwork() const {
239 return status
.status() != net::URLRequestStatus::CANCELED
&&
240 response_info
.network_accessed
;
243 void DomainReliabilityMonitor::OnRequestLegComplete(
244 const RequestInfo
& request
) {
245 // Check these again because unit tests call this directly.
246 DCHECK(OnNetworkThread());
247 DCHECK(discard_uploads_set_
);
250 if (request
.response_info
.headers
.get())
251 response_code
= request
.response_info
.headers
->response_code();
254 std::string beacon_status
;
256 int error_code
= net::OK
;
257 if (request
.status
.status() == net::URLRequestStatus::FAILED
)
258 error_code
= request
.status
.error();
260 // Ignore requests where:
261 // 1. The request did not access the network.
262 // 2. The request is not supposed to send cookies (to avoid associating the
263 // request with any potentially unique data in the config).
264 // 3. The request was itself a Domain Reliability upload (to avoid loops).
265 // 4. There is no matching beacon status for the error or HTTP response code
266 // (to avoid leaking network-local errors).
267 if (!request
.AccessedNetwork() ||
268 (request
.load_flags
& net::LOAD_DO_NOT_SEND_COOKIES
) ||
270 !GetDomainReliabilityBeaconStatus(
271 error_code
, response_code
, &beacon_status
)) {
275 DomainReliabilityBeacon beacon
;
276 beacon
.status
= beacon_status
;
277 beacon
.chrome_error
= error_code
;
278 // If the response was cached, the socket address was the address that the
279 // response was originally received from, so it shouldn't be copied into the
282 // TODO(ttuttle): Wire up a way to get the real socket address in that case.
283 if (!request
.response_info
.was_cached
&&
284 !request
.response_info
.was_fetched_via_proxy
) {
285 beacon
.server_ip
= request
.response_info
.socket_address
.host();
287 beacon
.protocol
= GetDomainReliabilityProtocol(
288 request
.response_info
.connection_info
,
289 request
.response_info
.ssl_info
.is_valid());
290 beacon
.http_response_code
= response_code
;
291 beacon
.start_time
= request
.load_timing_info
.request_start
;
292 beacon
.elapsed
= time_
->NowTicks() - beacon
.start_time
;
293 beacon
.domain
= request
.url
.host();
294 context_manager_
.RouteBeacon(request
.url
, beacon
);
297 base::WeakPtr
<DomainReliabilityMonitor
>
298 DomainReliabilityMonitor::MakeWeakPtr() {
299 return weak_factory_
.GetWeakPtr();
302 } // namespace domain_reliability