monitor.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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/message_loop/message_loop.h"
10#include "base/single_thread_task_runner.h"
11#include "base/time/time.h"
12#include "components/domain_reliability/baked_in_configs.h"
13#include "content/public/browser/browser_thread.h"
14#include "net/base/load_flags.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
19namespace {
20
21bool OnIOThread() {
22  return content::BrowserThread::CurrentlyOn(content::BrowserThread::IO);
23}
24
25// Shamelessly stolen from net/tools/get_server_time/get_server_time.cc.
26// TODO(ttuttle): Merge them, if possible.
27class TrivialURLRequestContextGetter : public net::URLRequestContextGetter {
28 public:
29  TrivialURLRequestContextGetter(
30      net::URLRequestContext* context,
31      const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner)
32      : context_(context),
33        main_task_runner_(main_task_runner) {}
34
35  // net::URLRequestContextGetter implementation:
36  virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE {
37    return context_;
38  }
39
40  virtual scoped_refptr<base::SingleThreadTaskRunner>
41  GetNetworkTaskRunner() const OVERRIDE {
42    return main_task_runner_;
43  }
44
45 private:
46  virtual ~TrivialURLRequestContextGetter() {}
47
48  net::URLRequestContext* context_;
49  const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
50};
51
52}  // namespace
53
54namespace domain_reliability {
55
56DomainReliabilityMonitor::DomainReliabilityMonitor(
57    net::URLRequestContext* url_request_context)
58    : time_(new ActualTime()),
59      url_request_context_getter_(scoped_refptr<net::URLRequestContextGetter>(
60          new TrivialURLRequestContextGetter(
61              url_request_context,
62              content::BrowserThread::GetMessageLoopProxyForThread(
63                  content::BrowserThread::IO)))),
64      scheduler_params_(
65          DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()),
66      dispatcher_(time_.get()),
67      uploader_(
68          DomainReliabilityUploader::Create(url_request_context_getter_)) {
69  DCHECK(OnIOThread());
70}
71
72DomainReliabilityMonitor::DomainReliabilityMonitor(
73    net::URLRequestContext* url_request_context,
74    scoped_ptr<MockableTime> time)
75    : time_(time.Pass()),
76      url_request_context_getter_(scoped_refptr<net::URLRequestContextGetter>(
77          new TrivialURLRequestContextGetter(
78              url_request_context,
79              content::BrowserThread::GetMessageLoopProxyForThread(
80                  content::BrowserThread::IO)))),
81      scheduler_params_(
82          DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()),
83      dispatcher_(time_.get()),
84      uploader_(
85          DomainReliabilityUploader::Create(url_request_context_getter_)) {
86  DCHECK(OnIOThread());
87}
88
89DomainReliabilityMonitor::~DomainReliabilityMonitor() {
90  DCHECK(OnIOThread());
91  STLDeleteContainerPairSecondPointers(
92      contexts_.begin(), contexts_.end());
93}
94
95void DomainReliabilityMonitor::AddBakedInConfigs() {
96  base::Time now = base::Time::Now();
97  for (size_t i = 0; kBakedInJsonConfigs[i]; ++i) {
98    std::string json(kBakedInJsonConfigs[i]);
99    scoped_ptr<const DomainReliabilityConfig> config =
100        DomainReliabilityConfig::FromJSON(json);
101    if (config && config->IsExpired(now)) {
102      LOG(WARNING) << "Baked-in Domain Reliability config for "
103                   << config->domain << " is expired.";
104      continue;
105    }
106    AddContext(config.Pass());
107  }
108}
109
110void DomainReliabilityMonitor::OnBeforeRedirect(net::URLRequest* request) {
111  DCHECK(OnIOThread());
112  RequestInfo request_info(*request);
113  // Record the redirect itself in addition to the final request.
114  OnRequestLegComplete(request_info);
115}
116
117void DomainReliabilityMonitor::OnCompleted(net::URLRequest* request,
118                                           bool started) {
119  DCHECK(OnIOThread());
120  if (!started)
121    return;
122  RequestInfo request_info(*request);
123  if (request_info.DefinitelyReachedNetwork()) {
124    OnRequestLegComplete(request_info);
125    // A request was just using the network, so now is a good time to run any
126    // pending and eligible uploads.
127    dispatcher_.RunEligibleTasks();
128  }
129}
130
131DomainReliabilityContext* DomainReliabilityMonitor::AddContextForTesting(
132    scoped_ptr<const DomainReliabilityConfig> config) {
133  return AddContext(config.Pass());
134}
135
136DomainReliabilityMonitor::RequestInfo::RequestInfo() {}
137
138DomainReliabilityMonitor::RequestInfo::RequestInfo(
139    const net::URLRequest& request)
140    : url(request.url()),
141      status(request.status()),
142      response_code(-1),
143      socket_address(request.GetSocketAddress()),
144      was_cached(request.was_cached()),
145      load_flags(request.load_flags()) {
146  request.GetLoadTimingInfo(&load_timing_info);
147  // Can't get response code of a canceled request -- there's no transaction.
148  if (status.status() != net::URLRequestStatus::CANCELED)
149    response_code = request.GetResponseCode();
150}
151
152DomainReliabilityMonitor::RequestInfo::~RequestInfo() {}
153
154bool DomainReliabilityMonitor::RequestInfo::DefinitelyReachedNetwork() const {
155  return status.status() != net::URLRequestStatus::CANCELED && !was_cached;
156}
157
158DomainReliabilityContext* DomainReliabilityMonitor::AddContext(
159    scoped_ptr<const DomainReliabilityConfig> config) {
160  DCHECK(config);
161  DCHECK(config->IsValid());
162
163  // Grab domain before we config.Pass().
164  std::string domain = config->domain;
165
166  DomainReliabilityContext* context = new DomainReliabilityContext(
167      time_.get(),
168      scheduler_params_,
169      &dispatcher_,
170      uploader_.get(),
171      config.Pass());
172
173  std::pair<ContextMap::iterator, bool> map_it =
174      contexts_.insert(make_pair(domain, context));
175  // Make sure the domain wasn't already in the map.
176  DCHECK(map_it.second);
177
178  return map_it.first->second;
179}
180
181void DomainReliabilityMonitor::OnRequestLegComplete(
182    const RequestInfo& request) {
183  if (!request.DefinitelyReachedNetwork())
184    return;
185
186  // Don't monitor requests that are not sending cookies, since sending a beacon
187  // for such requests may allow the server to correlate that request with the
188  // user (by correlating a particular config).
189  if (request.load_flags & net::LOAD_DO_NOT_SEND_COOKIES)
190    return;
191
192  ContextMap::iterator it = contexts_.find(request.url.host());
193  if (it == contexts_.end())
194    return;
195  DomainReliabilityContext* context = it->second;
196
197  std::string beacon_status;
198  bool got_status = DomainReliabilityUtil::GetBeaconStatus(
199      request.status.error(),
200      request.response_code,
201      &beacon_status);
202  if (!got_status)
203    return;
204
205  DomainReliabilityBeacon beacon;
206  beacon.status = beacon_status;
207  beacon.chrome_error = request.status.error();
208  beacon.server_ip = request.socket_address.host();
209  beacon.http_response_code = request.response_code;
210  beacon.start_time = request.load_timing_info.request_start;
211  beacon.elapsed = time_->NowTicks() - beacon.start_time;
212  context->AddBeacon(beacon, request.url);
213}
214
215}  // namespace domain_reliability
216