1 // Copyright (c) 2011 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 "chrome/browser/autofill/autofill_download.h" 6 7 #include <algorithm> 8 #include <ostream> 9 #include <vector> 10 11 #ifdef ANDROID 12 #include "android/jni/autofill_request_url.h" 13 #endif 14 #include "base/logging.h" 15 #include "base/rand_util.h" 16 #include "base/stl_util-inl.h" 17 #include "base/string_util.h" 18 #include "chrome/browser/autofill/autofill_metrics.h" 19 #include "chrome/browser/autofill/autofill_xml_parser.h" 20 #include "chrome/browser/autofill/form_structure.h" 21 #include "chrome/browser/prefs/pref_service.h" 22 #include "chrome/browser/profiles/profile.h" 23 #include "chrome/common/pref_names.h" 24 #include "googleurl/src/gurl.h" 25 #include "net/http/http_response_headers.h" 26 #include "third_party/libjingle/source/talk/xmllite/xmlparser.h" 27 28 #define AUTO_FILL_QUERY_SERVER_REQUEST_URL \ 29 "http://toolbarqueries.clients.google.com:80/tbproxy/af/query" 30 #define AUTO_FILL_UPLOAD_SERVER_REQUEST_URL \ 31 "http://toolbarqueries.clients.google.com:80/tbproxy/af/upload" 32 #define AUTO_FILL_QUERY_SERVER_NAME_START_IN_HEADER "GFE/" 33 34 namespace { 35 const size_t kMaxFormCacheSize = 16; 36 }; 37 38 struct AutofillDownloadManager::FormRequestData { 39 std::vector<std::string> form_signatures; 40 AutofillRequestType request_type; 41 }; 42 43 #ifdef ANDROID 44 // Taken from autofill_manager.cc 45 const double kAutoFillPositiveUploadRateDefaultValue = 0.01; 46 const double kAutoFillNegativeUploadRateDefaultValue = 0.01; 47 #endif 48 49 AutofillDownloadManager::AutofillDownloadManager(Profile* profile) 50 : profile_(profile), 51 observer_(NULL), 52 max_form_cache_size_(kMaxFormCacheSize), 53 next_query_request_(base::Time::Now()), 54 next_upload_request_(base::Time::Now()), 55 positive_upload_rate_(0), 56 negative_upload_rate_(0), 57 fetcher_id_for_unittest_(0) { 58 // |profile_| could be NULL in some unit-tests. 59 #ifdef ANDROID 60 positive_upload_rate_ = kAutoFillPositiveUploadRateDefaultValue; 61 negative_upload_rate_ = kAutoFillNegativeUploadRateDefaultValue; 62 #else 63 if (profile_) { 64 PrefService* preferences = profile_->GetPrefs(); 65 positive_upload_rate_ = 66 preferences->GetDouble(prefs::kAutofillPositiveUploadRate); 67 negative_upload_rate_ = 68 preferences->GetDouble(prefs::kAutofillNegativeUploadRate); 69 } 70 #endif 71 } 72 73 AutofillDownloadManager::~AutofillDownloadManager() { 74 STLDeleteContainerPairFirstPointers(url_fetchers_.begin(), 75 url_fetchers_.end()); 76 } 77 78 void AutofillDownloadManager::SetObserver( 79 AutofillDownloadManager::Observer *observer) { 80 if (observer) { 81 DCHECK(!observer_); 82 observer_ = observer; 83 } else { 84 observer_ = NULL; 85 } 86 } 87 88 bool AutofillDownloadManager::StartQueryRequest( 89 const ScopedVector<FormStructure>& forms, 90 const AutofillMetrics& metric_logger) { 91 if (next_query_request_ > base::Time::Now()) { 92 // We are in back-off mode: do not do the request. 93 return false; 94 } 95 std::string form_xml; 96 FormRequestData request_data; 97 if (!FormStructure::EncodeQueryRequest(forms, &request_data.form_signatures, 98 &form_xml)) { 99 return false; 100 } 101 102 request_data.request_type = AutofillDownloadManager::REQUEST_QUERY; 103 metric_logger.Log(AutofillMetrics::QUERY_SENT); 104 105 std::string query_data; 106 if (CheckCacheForQueryRequest(request_data.form_signatures, &query_data)) { 107 VLOG(1) << "AutofillDownloadManager: query request has been retrieved from" 108 << "the cache"; 109 if (observer_) 110 observer_->OnLoadedAutofillHeuristics(query_data); 111 return true; 112 } 113 114 return StartRequest(form_xml, request_data); 115 } 116 117 bool AutofillDownloadManager::StartUploadRequest( 118 const FormStructure& form, bool form_was_matched) { 119 if (next_upload_request_ > base::Time::Now()) { 120 // We are in back-off mode: do not do the request. 121 return false; 122 } 123 124 // Check if we need to upload form. 125 double upload_rate = form_was_matched ? GetPositiveUploadRate() : 126 GetNegativeUploadRate(); 127 if (base::RandDouble() > upload_rate) { 128 VLOG(1) << "AutofillDownloadManager: Upload request is ignored"; 129 // If we ever need notification that upload was skipped, add it here. 130 return false; 131 } 132 std::string form_xml; 133 if (!form.EncodeUploadRequest(form_was_matched, &form_xml)) 134 return false; 135 136 FormRequestData request_data; 137 request_data.form_signatures.push_back(form.FormSignature()); 138 request_data.request_type = AutofillDownloadManager::REQUEST_UPLOAD; 139 140 return StartRequest(form_xml, request_data); 141 } 142 143 bool AutofillDownloadManager::CancelRequest( 144 const std::string& form_signature, 145 AutofillDownloadManager::AutofillRequestType request_type) { 146 for (std::map<URLFetcher *, FormRequestData>::iterator it = 147 url_fetchers_.begin(); 148 it != url_fetchers_.end(); 149 ++it) { 150 if (std::find(it->second.form_signatures.begin(), 151 it->second.form_signatures.end(), form_signature) != 152 it->second.form_signatures.end() && 153 it->second.request_type == request_type) { 154 delete it->first; 155 url_fetchers_.erase(it); 156 return true; 157 } 158 } 159 return false; 160 } 161 162 double AutofillDownloadManager::GetPositiveUploadRate() const { 163 return positive_upload_rate_; 164 } 165 166 double AutofillDownloadManager::GetNegativeUploadRate() const { 167 return negative_upload_rate_; 168 } 169 170 void AutofillDownloadManager::SetPositiveUploadRate(double rate) { 171 if (rate == positive_upload_rate_) 172 return; 173 positive_upload_rate_ = rate; 174 DCHECK_GE(rate, 0.0); 175 DCHECK_LE(rate, 1.0); 176 DCHECK(profile_); 177 #ifndef ANDROID 178 PrefService* preferences = profile_->GetPrefs(); 179 preferences->SetDouble(prefs::kAutofillPositiveUploadRate, rate); 180 #endif 181 } 182 183 void AutofillDownloadManager::SetNegativeUploadRate(double rate) { 184 if (rate == negative_upload_rate_) 185 return; 186 negative_upload_rate_ = rate; 187 DCHECK_GE(rate, 0.0); 188 DCHECK_LE(rate, 1.0); 189 DCHECK(profile_); 190 #ifndef ANDROID 191 PrefService* preferences = profile_->GetPrefs(); 192 preferences->SetDouble(prefs::kAutofillNegativeUploadRate, rate); 193 #endif 194 } 195 196 bool AutofillDownloadManager::StartRequest( 197 const std::string& form_xml, 198 const FormRequestData& request_data) { 199 net::URLRequestContextGetter* request_context = 200 #ifdef ANDROID 201 // On Android, use the webview request context getter which was passed 202 // through in the WebAutoFill::init() method in WebKit. 203 profile_->GetRequestContext(); 204 #else 205 Profile::GetDefaultRequestContext(); 206 #endif 207 // Check if default request context is NULL: this very rarely happens, 208 // I think, this could happen only if user opens chrome with some pages 209 // loading the forms immediately; I cannot reproduce this even in that 210 // scenario, but bug 74492 shows it happened at least once. In that case bail 211 // out and fall back on our own heuristics. 212 if (!request_context) 213 return false; 214 std::string request_url; 215 if (request_data.request_type == AutofillDownloadManager::REQUEST_QUERY) 216 request_url = AUTO_FILL_QUERY_SERVER_REQUEST_URL; 217 else 218 request_url = AUTO_FILL_UPLOAD_SERVER_REQUEST_URL; 219 220 #ifdef ANDROID 221 if (request_data.request_type == AutofillDownloadManager::REQUEST_QUERY) { 222 // Ask the platform what URL to use for Autofill. If the 223 // platform doesn't know, bail and rely on the heuristics 224 // we've gathered. 225 request_url = android::AutofillRequestUrl::GetQueryUrl(); 226 if (request_url.empty()) 227 return false; 228 } 229 #endif 230 231 // Id is ignored for regular chrome, in unit test id's for fake fetcher 232 // factory will be 0, 1, 2, ... 233 URLFetcher *fetcher = URLFetcher::Create(fetcher_id_for_unittest_++, 234 GURL(request_url), 235 URLFetcher::POST, 236 this); 237 url_fetchers_[fetcher] = request_data; 238 fetcher->set_automatically_retry_on_5xx(false); 239 fetcher->set_request_context(request_context); 240 fetcher->set_upload_data("text/plain", form_xml); 241 fetcher->Start(); 242 return true; 243 } 244 245 void AutofillDownloadManager::CacheQueryRequest( 246 const std::vector<std::string>& forms_in_query, 247 const std::string& query_data) { 248 std::string signature = GetCombinedSignature(forms_in_query); 249 for (QueryRequestCache::iterator it = cached_forms_.begin(); 250 it != cached_forms_.end(); ++it) { 251 if (it->first == signature) { 252 // We hit the cache, move to the first position and return. 253 std::pair<std::string, std::string> data = *it; 254 cached_forms_.erase(it); 255 cached_forms_.push_front(data); 256 return; 257 } 258 } 259 std::pair<std::string, std::string> data; 260 data.first = signature; 261 data.second = query_data; 262 cached_forms_.push_front(data); 263 while (cached_forms_.size() > max_form_cache_size_) 264 cached_forms_.pop_back(); 265 } 266 267 bool AutofillDownloadManager::CheckCacheForQueryRequest( 268 const std::vector<std::string>& forms_in_query, 269 std::string* query_data) const { 270 std::string signature = GetCombinedSignature(forms_in_query); 271 for (QueryRequestCache::const_iterator it = cached_forms_.begin(); 272 it != cached_forms_.end(); ++it) { 273 if (it->first == signature) { 274 // We hit the cache, fill the data and return. 275 *query_data = it->second; 276 return true; 277 } 278 } 279 return false; 280 } 281 282 std::string AutofillDownloadManager::GetCombinedSignature( 283 const std::vector<std::string>& forms_in_query) const { 284 size_t total_size = forms_in_query.size(); 285 for (size_t i = 0; i < forms_in_query.size(); ++i) 286 total_size += forms_in_query[i].length(); 287 std::string signature; 288 289 signature.reserve(total_size); 290 291 for (size_t i = 0; i < forms_in_query.size(); ++i) { 292 if (i) 293 signature.append(","); 294 signature.append(forms_in_query[i]); 295 } 296 return signature; 297 } 298 299 void AutofillDownloadManager::OnURLFetchComplete( 300 const URLFetcher* source, 301 const GURL& url, 302 const net::URLRequestStatus& status, 303 int response_code, 304 const ResponseCookies& cookies, 305 const std::string& data) { 306 std::map<URLFetcher *, FormRequestData>::iterator it = 307 url_fetchers_.find(const_cast<URLFetcher*>(source)); 308 if (it == url_fetchers_.end()) { 309 // Looks like crash on Mac is possibly caused with callback entering here 310 // with unknown fetcher when network is refreshed. 311 return; 312 } 313 std::string type_of_request( 314 it->second.request_type == AutofillDownloadManager::REQUEST_QUERY ? 315 "query" : "upload"); 316 const int kHttpResponseOk = 200; 317 const int kHttpInternalServerError = 500; 318 const int kHttpBadGateway = 502; 319 const int kHttpServiceUnavailable = 503; 320 321 CHECK(it->second.form_signatures.size()); 322 if (response_code != kHttpResponseOk) { 323 bool back_off = false; 324 std::string server_header; 325 switch (response_code) { 326 case kHttpBadGateway: 327 if (!source->response_headers()->EnumerateHeader(NULL, "server", 328 &server_header) || 329 StartsWithASCII(server_header.c_str(), 330 AUTO_FILL_QUERY_SERVER_NAME_START_IN_HEADER, 331 false) != 0) 332 break; 333 // Bad gateway was received from Autofill servers. Fall through to back 334 // off. 335 case kHttpInternalServerError: 336 case kHttpServiceUnavailable: 337 back_off = true; 338 break; 339 } 340 341 if (back_off) { 342 base::Time back_off_time(base::Time::Now() + source->backoff_delay()); 343 if (it->second.request_type == AutofillDownloadManager::REQUEST_QUERY) { 344 next_query_request_ = back_off_time; 345 } else { 346 next_upload_request_ = back_off_time; 347 } 348 } 349 350 LOG(WARNING) << "AutofillDownloadManager: " << type_of_request 351 << " request has failed with response " << response_code; 352 if (observer_) { 353 observer_->OnHeuristicsRequestError(it->second.form_signatures[0], 354 it->second.request_type, 355 response_code); 356 } 357 } else { 358 VLOG(1) << "AutofillDownloadManager: " << type_of_request 359 << " request has succeeded"; 360 if (it->second.request_type == AutofillDownloadManager::REQUEST_QUERY) { 361 CacheQueryRequest(it->second.form_signatures, data); 362 if (observer_) 363 observer_->OnLoadedAutofillHeuristics(data); 364 } else { 365 double new_positive_upload_rate = 0; 366 double new_negative_upload_rate = 0; 367 AutofillUploadXmlParser parse_handler(&new_positive_upload_rate, 368 &new_negative_upload_rate); 369 buzz::XmlParser parser(&parse_handler); 370 parser.Parse(data.data(), data.length(), true); 371 if (parse_handler.succeeded()) { 372 SetPositiveUploadRate(new_positive_upload_rate); 373 SetNegativeUploadRate(new_negative_upload_rate); 374 } 375 376 if (observer_) 377 observer_->OnUploadedAutofillHeuristics(it->second.form_signatures[0]); 378 } 379 } 380 delete it->first; 381 url_fetchers_.erase(it); 382 } 383