Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / components / domain_reliability / monitor.cc
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.
4
5 #include "components/domain_reliability/monitor.h"
6
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"
18
19 namespace domain_reliability {
20
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);
38 }
39
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);
58 }
59
60 DomainReliabilityMonitor::~DomainReliabilityMonitor() {
61   if (moved_to_network_thread_)
62     DCHECK(OnNetworkThread());
63   else
64     DCHECK(OnPrefThread());
65
66   ClearContexts();
67 }
68
69 void DomainReliabilityMonitor::MoveToNetworkThread() {
70   DCHECK(OnPrefThread());
71   DCHECK(!moved_to_network_thread_);
72
73   reporting_pref_.MoveToThread(network_task_runner_);
74   moved_to_network_thread_ = true;
75 }
76
77 void DomainReliabilityMonitor::DestroyReportingPref() {
78   DCHECK(OnPrefThread());
79
80   reporting_pref_.Destroy();
81 }
82
83 void DomainReliabilityMonitor::InitURLRequestContext(
84     net::URLRequestContext* url_request_context) {
85   DCHECK(OnNetworkThread());
86   DCHECK(moved_to_network_thread_);
87
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);
92 }
93
94 void DomainReliabilityMonitor::InitURLRequestContext(
95     scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) {
96   DCHECK(OnNetworkThread());
97   DCHECK(moved_to_network_thread_);
98
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());
103
104   uploader_ = DomainReliabilityUploader::Create(url_request_context_getter);
105   // Make sure the uploader is sending or discarding uploads according to pref.
106   OnReportingPrefChanged();
107 }
108
109 void DomainReliabilityMonitor::AddBakedInConfigs() {
110   DCHECK(OnNetworkThread());
111
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;
121     }
122     AddContext(config.Pass());
123   }
124 }
125
126 void DomainReliabilityMonitor::OnBeforeRedirect(net::URLRequest* request) {
127   DCHECK(OnNetworkThread());
128
129   // Record the redirect itself in addition to the final request.
130   OnRequestLegComplete(RequestInfo(*request));
131 }
132
133 void DomainReliabilityMonitor::OnCompleted(net::URLRequest* request,
134                                            bool started) {
135   DCHECK(OnNetworkThread());
136
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();
145   }
146 }
147
148 void DomainReliabilityMonitor::ClearBrowsingData(
149    DomainReliabilityClearMode mode) {
150   DCHECK(OnNetworkThread());
151
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;
158     };
159     case CLEAR_CONTEXTS:
160       ClearContexts();
161       break;
162     case MAX_CLEAR_MODE:
163       NOTREACHED();
164   }
165 }
166
167 scoped_ptr<base::Value> DomainReliabilityMonitor::GetWebUIData() const {
168   DCHECK(OnNetworkThread());
169
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());
175   }
176
177   base::DictionaryValue* data_value = new base::DictionaryValue();
178   data_value->Set("contexts", contexts_value);
179
180   return scoped_ptr<base::Value>(data_value);
181 }
182
183 DomainReliabilityContext* DomainReliabilityMonitor::AddContextForTesting(
184     scoped_ptr<const DomainReliabilityConfig> config) {
185   DCHECK(OnNetworkThread());
186
187   return AddContext(config.Pass());
188 }
189
190 DomainReliabilityMonitor::RequestInfo::RequestInfo() {}
191
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);
200 }
201
202 DomainReliabilityMonitor::RequestInfo::~RequestInfo() {}
203
204 bool DomainReliabilityMonitor::RequestInfo::AccessedNetwork() const {
205   return status.status() != net::URLRequestStatus::CANCELED &&
206      response_info.network_accessed;
207 }
208
209 DomainReliabilityContext* DomainReliabilityMonitor::AddContext(
210     scoped_ptr<const DomainReliabilityConfig> config) {
211   DCHECK(OnNetworkThread());
212   DCHECK(config);
213   DCHECK(config->IsValid());
214
215   // Grab a copy of the domain before transferring ownership of |config|.
216   std::string domain = config->domain;
217
218   DomainReliabilityContext* context =
219       new DomainReliabilityContext(time_.get(),
220                                    scheduler_params_,
221                                    upload_reporter_string_,
222                                    &dispatcher_,
223                                    uploader_.get(),
224                                    config.Pass());
225
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);
230
231   return map_it.first->second;
232 }
233
234 void DomainReliabilityMonitor::ClearContexts() {
235   STLDeleteContainerPairSecondPointers(
236       contexts_.begin(), contexts_.end());
237   contexts_.clear();
238 }
239
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;
248
249   int error_code = net::OK;
250   if (request.status.status() == net::URLRequestStatus::FAILED)
251     error_code = request.status.error();
252
253   DomainReliabilityContext* context = GetContextForHost(request.url.host());
254
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;
270   }
271
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   beacon.domain = request.url.host();
286   context->OnBeacon(request.url, beacon);
287 }
288
289 void DomainReliabilityMonitor::InitReportingPref(
290     PrefService* local_state_pref_service,
291     const char* reporting_pref_name) {
292   reporting_pref_.Init(
293       reporting_pref_name,
294       local_state_pref_service,
295       base::Bind(&DomainReliabilityMonitor::OnReportingPrefChanged,
296                  base::Unretained(this)));
297 }
298
299 void DomainReliabilityMonitor::OnReportingPrefChanged() {
300   DCHECK(OnNetworkThread());
301
302   // When metrics reporting is disabled, discard Domain Reliability uploads.
303   if (uploader_)
304     uploader_->set_discard_uploads(!*reporting_pref_);
305 }
306
307 // TODO(ttuttle): Keep a separate wildcard_contexts_ map to avoid having to
308 // prepend '*.' to domains.
309 DomainReliabilityContext* DomainReliabilityMonitor::GetContextForHost(
310     const std::string& host) const {
311   DCHECK(OnNetworkThread());
312
313   ContextMap::const_iterator context_it;
314
315   context_it = contexts_.find(host);
316   if (context_it != contexts_.end())
317     return context_it->second;
318
319   std::string host_with_asterisk = "*." + host;
320   context_it = contexts_.find(host_with_asterisk);
321   if (context_it != contexts_.end())
322     return context_it->second;
323
324   size_t dot_pos = host.find('.');
325   if (dot_pos == std::string::npos)
326     return NULL;
327
328   // TODO(ttuttle): Make sure parent is not in PSL before using.
329
330   std::string parent_with_asterisk = "*." + host.substr(dot_pos + 1);
331   context_it = contexts_.find(parent_with_asterisk);
332   if (context_it != contexts_.end())
333     return context_it->second;
334
335   return NULL;
336 }
337
338 base::WeakPtr<DomainReliabilityMonitor>
339 DomainReliabilityMonitor::MakeWeakPtr() {
340   return weak_factory_.GetWeakPtr();
341 }
342
343 }  // namespace domain_reliability