Home | History | Annotate | Download | only in domain_reliability
      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/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"
     20 
     21 namespace domain_reliability {
     22 
     23 DomainReliabilityMonitor::DomainReliabilityMonitor(
     24     const std::string& upload_reporter_string)
     25     : time_(new ActualTime()),
     26       upload_reporter_string_(upload_reporter_string),
     27       scheduler_params_(
     28           DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()),
     29       dispatcher_(time_.get()),
     30       was_cleared_(false),
     31       cleared_mode_(MAX_CLEAR_MODE),
     32       weak_factory_(this) {}
     33 
     34 DomainReliabilityMonitor::DomainReliabilityMonitor(
     35     const std::string& upload_reporter_string,
     36     scoped_ptr<MockableTime> time)
     37     : time_(time.Pass()),
     38       upload_reporter_string_(upload_reporter_string),
     39       scheduler_params_(
     40           DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults()),
     41       dispatcher_(time_.get()),
     42       was_cleared_(false),
     43       cleared_mode_(MAX_CLEAR_MODE),
     44       weak_factory_(this) {}
     45 
     46 DomainReliabilityMonitor::~DomainReliabilityMonitor() {
     47   ClearContexts();
     48 }
     49 
     50 void DomainReliabilityMonitor::Init(
     51     net::URLRequestContext* url_request_context,
     52     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
     53   DCHECK(!thread_checker_);
     54 
     55   scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
     56       new net::TrivialURLRequestContextGetter(url_request_context,
     57                                               task_runner);
     58   Init(url_request_context_getter);
     59 }
     60 
     61 void DomainReliabilityMonitor::Init(
     62     scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) {
     63   DCHECK(!thread_checker_);
     64 
     65   DCHECK(url_request_context_getter->GetNetworkTaskRunner()->
     66          RunsTasksOnCurrentThread());
     67 
     68   uploader_ = DomainReliabilityUploader::Create(url_request_context_getter);
     69   thread_checker_.reset(new base::ThreadChecker());
     70 }
     71 
     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.";
     82       continue;
     83     }
     84     AddContext(config.Pass());
     85   }
     86 }
     87 
     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));
     92 }
     93 
     94 void DomainReliabilityMonitor::OnCompleted(net::URLRequest* request,
     95                                            bool started) {
     96   DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
     97   if (!started)
     98     return;
     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();
    105   }
    106 }
    107 
    108 void DomainReliabilityMonitor::ClearBrowsingData(
    109    DomainReliabilityClearMode mode) {
    110   DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
    111 
    112   was_cleared_ = true;
    113   cleared_mode_ = mode;
    114 
    115   switch (mode) {
    116     case CLEAR_BEACONS: {
    117       ContextMap::const_iterator it;
    118       for (it = contexts_.begin(); it != contexts_.end(); ++it)
    119         it->second->ClearBeacons();
    120       break;
    121     };
    122     case CLEAR_CONTEXTS:
    123       ClearContexts();
    124       break;
    125     case MAX_CLEAR_MODE:
    126       NOTREACHED();
    127   }
    128 }
    129 
    130 DomainReliabilityContext* DomainReliabilityMonitor::AddContextForTesting(
    131     scoped_ptr<const DomainReliabilityConfig> config) {
    132   DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
    133   return AddContext(config.Pass());
    134 }
    135 
    136 DomainReliabilityMonitor::RequestInfo::RequestInfo() {}
    137 
    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);
    146 }
    147 
    148 DomainReliabilityMonitor::RequestInfo::~RequestInfo() {}
    149 
    150 bool DomainReliabilityMonitor::RequestInfo::AccessedNetwork() const {
    151   return status.status() != net::URLRequestStatus::CANCELED &&
    152      response_info.network_accessed;
    153 }
    154 
    155 DomainReliabilityContext* DomainReliabilityMonitor::AddContext(
    156     scoped_ptr<const DomainReliabilityConfig> config) {
    157   DCHECK(config);
    158   DCHECK(config->IsValid());
    159 
    160   // Grab a copy of the domain before transferring ownership of |config|.
    161   std::string domain = config->domain;
    162 
    163   DomainReliabilityContext* context =
    164       new DomainReliabilityContext(time_.get(),
    165                                    scheduler_params_,
    166                                    upload_reporter_string_,
    167                                    &dispatcher_,
    168                                    uploader_.get(),
    169                                    config.Pass());
    170 
    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);
    175 
    176   return map_it.first->second;
    177 }
    178 
    179 void DomainReliabilityMonitor::ClearContexts() {
    180   STLDeleteContainerPairSecondPointers(
    181       contexts_.begin(), contexts_.end());
    182   contexts_.clear();
    183 }
    184 
    185 void DomainReliabilityMonitor::OnRequestLegComplete(
    186     const RequestInfo& request) {
    187   int response_code;
    188   if (request.response_info.headers)
    189     response_code = request.response_info.headers->response_code();
    190   else
    191     response_code = -1;
    192   ContextMap::iterator context_it;
    193   std::string beacon_status;
    194 
    195   int error_code = net::OK;
    196   if (request.status.status() == net::URLRequestStatus::FAILED)
    197     error_code = request.status.error();
    198 
    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) ||
    210       request.is_upload ||
    211       !GetDomainReliabilityBeaconStatus(
    212           error_code, response_code, &beacon_status)) {
    213     return;
    214   }
    215 
    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();
    221   else
    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);
    227 }
    228 
    229 base::WeakPtr<DomainReliabilityMonitor>
    230 DomainReliabilityMonitor::MakeWeakPtr() {
    231   return weak_factory_.GetWeakPtr();
    232 }
    233 
    234 }  // namespace domain_reliability
    235