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