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